Clean code is more than just aesthetics — it’s about writing code that scales with your team, reduces bugs, and makes onboarding easier. TypeScript’s type system gives you powerful tools to enforce good practices. Let’s explore some principles, with fresh examples that go beyond the classics.
1. Keep Names Simple and Focused
Bad:
type Book = {
bookTitle: string;
bookAuthor: string;
bookYear: number;
};
function logBookInfo(book: Book) {
console.log(`${book.bookTitle} by ${book.bookAuthor} (${book.bookYear})`);
}
Good:
type Book = {
title: string;
author: string;
year: number;
};
function logBookInfo(book: Book) {
console.log(`${book.title} by ${book.author} (${book.year})`);
}
2. Use Enums Instead of Raw Strings
Bad:
function getWeatherIcon(condition: string) {
if (condition === "rainy") return "🌧️";
if (condition === "sunny") return "☀️";
return "❓";
}
Good:
enum Weather {
Sunny = "sunny",
Rainy = "rainy",
Cloudy = "cloudy",
}
function getWeatherIcon(condition: Weather) {
switch (condition) {
case Weather.Sunny:
return "☀️";
case Weather.Rainy:
return "🌧️";
case Weather.Cloudy:
return "☁️";
}
}
3. Functions Should Say What They Do
Bad:
function update(data: number[]): number[] {
return data.map(x => x + 1);
}
Good:
function incrementScores(scores: number[]): number[] {
return scores.map(score => score + 1);
}
4. Prefer Functional Style for Data Transformation
Bad:
const orders = [{ price: 20 }, { price: 15 }, { price: 30 }];
let total = 0;
for (let i = 0; i < orders.length; i++) {
total += orders[i].price;
}
Good:
const orders = [{ price: 20 }, { price: 15 }, { price: 30 }];
const total = orders.reduce((sum, order) => sum + order.price, 0);
5. Use Positive Conditions
Bad:
function isPasswordNotValid(password: string): boolean {
return password.length < 8;
}
Good:
function isPasswordValid(password: string): boolean {
return password.length >= 8;
}
6. Favor Immutability
Bad:
interface Settings {
theme: string;
notifications: boolean;
}
const settings: Settings = { theme: "light", notifications: true };
settings.theme = "dark"; // accidental change
Good:
interface Settings {
readonly theme: string;
readonly notifications: boolean;
}
const settings: Settings = { theme: "light", notifications: true };
// settings.theme = "dark"; // compile-time error
7. Type vs Interface: Pick Intentionally
type PaymentMethod = "credit" | "paypal" | "crypto";
interface Storage {
save(data: string): void;
}
class LocalStorage implements Storage {
save(data: string) {
console.log("Saving:", data);
}
}
8. One Concept, One Test
Bad:
it("handles user creation and login", () => {
// does too much at once
});
Good:
it("should create a user", () => { /* ... */ });
it("should login with correct password", () => { /* ... */ });
it("should reject invalid login", () => { /* ... */ });
✅ Conclusion
Clean code in TypeScript is about clarity, predictability, and teamwork. By writing self-explanatory names, using enums, preferring immutability, and splitting responsibilities, you make your codebase easier to scale and maintain.
TypeScript gives you strong typing as a safety net — but discipline and consistency are what make codebases truly professional.