Lesson 19 of 20

TypeScript Best Practices

Type Safety Tips

Following these practices will help you get the most out of TypeScript's type system.

  • Avoid 'any' — use 'unknown' when the type is truly unknown
  • Enable strict mode in tsconfig.json
  • Use type inference — don't annotate when TypeScript can infer
  • Prefer interfaces for object shapes, types for unions and utilities
  • Use discriminated unions for complex state modeling
  • Keep types close to where they're used

Common Patterns

These patterns appear frequently in well-typed TypeScript codebases.

Example
// 1. Use 'as const' for literal types
const CONFIG = {
  apiUrl: "https://api.example.com",
  timeout: 5000
} as const;

// 2. Use satisfies for type checking without widening
type Colors = Record<string, [number, number, number]>;
const palette = {
  red: [255, 0, 0],
  green: [0, 255, 0]
} satisfies Colors;

// palette.red is still [number, number, number], not Colors

// 3. Branded types for type-safe IDs
type UserId = number & { __brand: 'UserId' };
type OrderId = number & { __brand: 'OrderId' };

function getUser(id: UserId) { /* ... */ }
// getUser(123 as OrderId); // Error!

Project Organization

Organize your TypeScript projects for maintainability and developer experience.

  • Keep shared types in a dedicated types/ directory
  • Use barrel exports (index.ts) for clean imports
  • Co-locate component types with their components
  • Use path aliases in tsconfig for cleaner imports
  • Run tsc --noEmit in CI to catch type errors
  • Use eslint with @typescript-eslint for additional checks