TypeScript
06 / 18

Configuration & Best Practices

TypeScript Configuration & Best Practices

tsconfig.json Essentials

{
  "compilerOptions": {
    // Language version
    "target": "ES2022",
    "lib": ["ES2022", "DOM"],
    
    // Module system
    "module": "ESNext",
    "moduleResolution": "bundler",
    
    // Strict type checking (recommended)
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "alwaysStrict": true,
    
    // Additional checks
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    
    // Emit
    "declaration": true,
    "sourceMap": true,
    "outDir": "./dist",
    
    // Interop
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true,
    
    // Advanced
    "skipLibCheck": true,
    "resolveJsonModule": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

Best Practices

1. Always Enable Strict Mode

// ❌ BAD: Without strict mode
function greet(name) {  // any type
  return name.toUpperCase();
}

greet(null); // Runtime error!

// ✅ GOOD: With strict mode
function greet(name: string): string {
  return name.toUpperCase();
}

// greet(null); // ✅ Compile error!

2. Avoid using any

// ❌ BAD
function process(data: any): any {
  return data.value;
}

// ✅ GOOD: Use unknown for true unknowns
function process(data: unknown): string {
  if (typeof data === 'object' && data !== null && 'value' in data) {
    return String((data as any).value);
  }
  throw new Error('Invalid data');
}

// ✅ BETTER: Use generics
function process<T extends { value: string }>(data: T): string {
  return data.value;
}

3. Use Type Inference

// ❌ Redundant
const name: string = 'John';
const age: number = 30;

// ✅ GOOD: Let TypeScript infer
const name = 'John';  // Inferred as string
const age = 30;       // Inferred as number

// ✅ Do annotate function returns (for clarity)
function getUser(): User {
  return { id: 1, name: 'John' };
}

4. Prefer Interfaces for Objects

// ✅ GOOD: Interface for objects
interface User {
  id: number;
  name: string;
}

interface Admin extends User {
  role: string;
}

// Use type for unions, primitives, tuples
type ID = string | number;
type Point = [number, number];

5. Use Const Assertions

// Without const assertion
const colors = ['red', 'green', 'blue']; // Type: string[]

// ✅ With const assertion
const colors = ['red', 'green', 'blue'] as const;
// Type: readonly ['red', 'green', 'blue']

const config = {
  apiUrl: 'https://api.example.com',
  timeout: 5000
} as const;
// All properties become readonly

// Use for exact literal types
type Color = typeof colors[number]; // 'red' | 'green' | 'blue'

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free