TypeScript Best Practices for Modern Development
Back to Home
Programming

TypeScript Best Practices for Modern Development

Ankit ChaubeyAnkit Chaubey
February 8, 2024
4 min read

TypeScript Best Practices

TypeScript has become the de facto standard for building large-scale JavaScript applications. Let's explore some best practices that will make your TypeScript code more robust and maintainable.

1. Use Strict Mode

Always enable strict mode in your tsconfig.json:

{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true
  }
}

2. Leverage Type Inference

TypeScript is smart about inferring types. Don't over-annotate:

// ❌ Unnecessary type annotation
const name: string = "Ankit";
 
// ✅ Let TypeScript infer
const name = "Ankit";

3. Use Interfaces Over Type Aliases (When Possible)

Interfaces are more extensible and provide better error messages:

// ✅ Preferred for objects
interface User {
  id: string;
  name: string;
  email: string;
}
 
// ✅ Good for unions and primitives
type Status = 'active' | 'inactive' | 'pending';

4. Avoid any Type

The any type defeats the purpose of TypeScript. Use unknown instead:

// ❌ Avoid
function process(data: any) {
  return data.value;
}
 
// ✅ Better
function process(data: unknown) {
  if (typeof data === 'object' && data !== null && 'value' in data) {
    return (data as { value: string }).value;
  }
}

5. Use Utility Types

TypeScript provides powerful utility types:

interface User {
  id: string;
  name: string;
  email: string;
  password: string;
}
 
// Partial - all properties optional
type UserUpdate = Partial<User>;
 
// Pick - select specific properties
type UserPublic = Pick<User, 'id' | 'name' | 'email'>;
 
// Omit - exclude specific properties
type UserSafe = Omit<User, 'password'>;
 
// Record - create object type
type UserRoles = Record<string, 'admin' | 'user' | 'guest'>;

6. Use Enums Carefully

Prefer const enums or string literal unions:

// ❌ Regular enum (generates runtime code)
enum Status {
  Active,
  Inactive
}
 
// ✅ Const enum (no runtime code)
const enum Status {
  Active,
  Inactive
}
 
// ✅ String literal union (my favorite)
type Status = 'active' | 'inactive';

7. Generic Constraints

Use constraints to make generics more specific:

// ✅ Constrained generic
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}
 
const user = { name: 'Ankit', age: 25 };
const name = getProperty(user, 'name'); // Type: string

8. Discriminated Unions

Create type-safe state machines:

type LoadingState = {
  status: 'loading';
};
 
type SuccessState<T> = {
  status: 'success';
  data: T;
};
 
type ErrorState = {
  status: 'error';
  error: Error;
};
 
type State<T> = LoadingState | SuccessState<T> | ErrorState;
 
function handleState<T>(state: State<T>) {
  switch (state.status) {
    case 'loading':
      return 'Loading...';
    case 'success':
      return state.data; // TypeScript knows data exists
    case 'error':
      return state.error.message; // TypeScript knows error exists
  }
}

9. Readonly Properties

Make properties immutable:

interface Config {
  readonly apiUrl: string;
  readonly timeout: number;
}
 
// Or use Readonly utility type
type Config = Readonly<{
  apiUrl: string;
  timeout: number;
}>;

10. Organize with Namespaces

Keep related types together:

namespace API {
  export interface User {
    id: string;
    name: string;
  }
  
  export interface Post {
    id: string;
    userId: string;
    title: string;
  }
  
  export type Response<T> = {
    data: T;
    error?: string;
  };
}
 
// Usage
const user: API.User = { id: '1', name: 'Ankit' };
const response: API.Response<API.User> = { data: user };

Conclusion

TypeScript is a powerful tool that, when used correctly, can significantly improve code quality and developer experience. Follow these best practices to write more maintainable, type-safe code.

Key Takeaways:

  • Enable strict mode
  • Let TypeScript infer types when possible
  • Avoid any, use unknown
  • Leverage utility types
  • Use discriminated unions for complex state

Share this post

Ankit Chaubey

About Ankit Chaubey

Full-stack developer passionate about modern web technologies

Related Posts