TypeScript Advanced Patterns for Professional Developers
Frontend

TypeScript Advanced Patterns for Professional Developers

M

Md Nayeem Hossain

Author

Dec 10, 2024
13 min read

TypeScript Advanced Patterns

Most developers know the basics of TypeScript: strings, numbers, and interfaces. But TypeScript's type system is incredibly powerful (Turing complete, actually!). Mastering advanced patterns allows you to write libraries and utilities that are robust and flexible.

Generics: Flexible Reusable Code

Generics allow you to write code that works with a variety of types rather than a single one. Think of them as "variables for types."

typescript
// Without generics, we lose type information
function getFirst(arr: any[]) {
  return arr[0]; // Return type is 'any'
}

// With generics
function getFirst<T>(arr: T[]): T | undefined {
  return arr[0];
}

const num = getFirst([1, 2, 3]); // Type is 'number'
const str = getFirst(["a", "b"]); // Type is 'string'

Utility Types

TypeScript comes with built-in utilities that transform types.

  • Partial<T>: Makes all properties optional.
  • Pick<T, K>: Selects a subset of properties.
  • Omit<T, K>: Removes a subset of properties.
  • typescript
    interface User {
      id: number;
      name: string;
      email: string;
      passwordHash: string;
    }
    
    // When updating a user, we might only provide some fields
    type UpdateUserDto = Partial<User>;
    
    // When displaying a user, we NEVER want to show the password
    type UserProfile = Omit<User, 'passwordHash'>;

    Discriminated Unions

    This is my favorite pattern for state management (like in Redux or useReducer). It uses a common literal field (usually type or kind) to let TypeScript narrow down the type.

    typescript
    type APIState = 
      | { status: "loading" }
      | { status: "success"; data: User[] }
      | { status: "error"; error: string };
    
    function handleState(state: APIState) {
      if (state.status === "loading") {
        // TypeScript knows 'data' and 'error' don't exist here
        return "Loading..."; 
      }
      
      if (state.status === "success") {
        // TypeScript knows 'data' exists here!
        return `Loaded ${state.data.length} users`;
      }
      
      if (state.status === "error") {
        return `Error: ${state.error}`;
      }
    }

    This pattern makes "impossible states" impossible to represent in your code, eliminating entire classes of bugs.

    TypeScript
    JavaScript
    Types
    Best Practices

    © 2026 Md Nayeem Hossain. All rights reserved.