Advanced TypeScript Patterns for Large-Scale Applications

Why Advanced TypeScript?

TypeScript's type system is powerful enough to catch bugs at compile time that would otherwise make it to production. Mastering it leads to more maintainable code.

Generic Constraints

// Constrained generic
function getProperty(obj: T, key: K): T[K] {
  return obj[key];
}

const user = { name: 'John', age: 30 };
const name = getProperty(user, 'name'); // type: string
const age = getProperty(user, 'age');   // type: number
// getProperty(user, 'invalid'); // Error!

// Generic with multiple constraints
interface HasId { id: string; }
interface HasTimestamp { createdAt: Date; }

function mergeEntities(
  a: T,
  b: Partial
): T {
  return { ...a, ...b };
}

Conditional Types

// Type that changes based on condition
type IsArray = T extends any[] ? true : false;

type A = IsArray; // true
type B = IsArray;   // false

// Extract return type from promise
type UnwrapPromise = T extends Promise ? U : T;

type Result = UnwrapPromise>; // string

// Conditional type for API responses
type ApiResponse = T extends undefined
  ? { success: boolean }
  : { success: boolean; data: T };

function handleResponse(data?: T): ApiResponse {
  return data !== undefined
    ? { success: true, data }
    : { success: true } as ApiResponse;
}

Mapped Types

// Make all properties optional
type Partial = {
  [K in keyof T]?: T[K];
};

// Make all properties required
type Required = {
  [K in keyof T]-?: T[K];
};

// Make all properties readonly
type Readonly = {
  readonly [K in keyof T]: T[K];
};

// Transform property types
type Getters = {
  [K in keyof T as `get${Capitalize}`]: () => T[K];
};

interface User {
  name: string;
  age: number;
}

type UserGetters = Getters;
// { getName: () => string; getAge: () => number; }

Template Literal Types

// Build string types programmatically
type EventName = 'click' | 'focus' | 'blur';
type EventHandler = `on${Capitalize}`;
// 'onClick' | 'onFocus' | 'onBlur'

// CSS property types
type CSSProperty = 'margin' | 'padding';
type CSSDirection = 'top' | 'right' | 'bottom' | 'left';
type CSSPropertyDirection = `${CSSProperty}-${CSSDirection}`;
// 'margin-top' | 'margin-right' | ... | 'padding-left'

// API route types
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type Route = '/users' | '/products';
type Endpoint = `${HttpMethod} ${Route}`;
// 'GET /users' | 'POST /users' | ...

Type Guards

// User-defined type guard
interface Dog { bark(): void; breed: string; }
interface Cat { meow(): void; lives: number; }

function isDog(pet: Dog | Cat): pet is Dog {
  return (pet as Dog).bark !== undefined;
}

function handlePet(pet: Dog | Cat) {
  if (isDog(pet)) {
    pet.bark(); // TypeScript knows it's a Dog
  } else {
    pet.meow(); // TypeScript knows it's a Cat
  }
}

// Assertion function
function assertIsString(value: unknown): asserts value is string {
  if (typeof value !== 'string') {
    throw new Error('Not a string');
  }
}

function process(input: unknown) {
  assertIsString(input);
  // input is now typed as string
  console.log(input.toUpperCase());
}

Discriminated Unions

// State machine types
type State = 
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'success'; data: User[] }
  | { status: 'error'; error: string };

function renderState(state: State): string {
  switch (state.status) {
    case 'idle':
      return 'Ready to fetch';
    case 'loading':
      return 'Loading...';
    case 'success':
      return `Found ${state.data.length} users`; // data is available
    case 'error':
      return `Error: ${state.error}`; // error is available
  }
}

// Exhaustive checking
function assertNever(x: never): never {
  throw new Error('Unexpected: ' + x);
}

function handle(state: State) {
  switch (state.status) {
    case 'idle': return;
    case 'loading': return;
    case 'success': return;
    case 'error': return;
    default: return assertNever(state); // Compile error if case missed
  }
}

Utility Types

// Pick specific properties
type UserPreview = Pick;

// Omit properties
type CreateUser = Omit;

// Record type for dictionaries
type UserCache = Record;

// Extract function parameters
type Params = Parameters;

// Extract return type
type Result = ReturnType;

// Extract awaited type
type Data = Awaited>;

Branded Types

// Prevent mixing up IDs
type UserId = string & { readonly brand: unique symbol };
type OrderId = string & { readonly brand: unique symbol };

function createUserId(id: string): UserId {
  return id as UserId;
}

function getUser(id: UserId): User { ... }
function getOrder(id: OrderId): Order { ... }

const userId = createUserId('123');
getUser(userId); // OK
// getOrder(userId); // Error! Can't use UserId where OrderId expected

Conclusion

Advanced TypeScript features help catch errors early and document your code's intent. Use them to build more reliable, maintainable applications.

๐Ÿ“šTechnical Insights & Industry Trends

Insights & Knowledge Hub

Explore in-depth articles on software development, digital transformation, and emerging technologies. Learn from real-world experience.

Browse by Topic

๐Ÿ…ฐ๏ธ
ArchitectureJan 2024

Why Angular SSR Beats React for SEO in 2024

A comprehensive comparison of server-side rendering implementations and their impact on search engine optimization, performance, and user experience.

๐Ÿ”Œ
ArchitectureDec 2023

Microservices: When to Use and When to Avoid

Understanding the trade-offs of microservices architecture and making the right choice for your organization's scale, complexity, and team structure.

๐Ÿ—๏ธ
System ArchitectureJan 2024

Essential Design Patterns for Enterprise Systems

Master the fundamental design patterns that every software architect should know for building scalable, maintainable enterprise applications.

๐Ÿ—๏ธ
System ArchitectureJan 2024

Domain-Driven Design: A Practical Guide

Learn how to apply Domain-Driven Design principles to create software that truly reflects business requirements and scales with organizational complexity.

๐Ÿ—๏ธ
System ArchitectureDec 2023

Event-Driven Architecture: Complete Implementation Guide

Build loosely coupled, scalable systems using event-driven architecture patterns with practical examples using Kafka, RabbitMQ, and Azure Service Bus.

๐Ÿ—๏ธ
System ArchitectureDec 2023

RESTful API Design: Best Practices and Patterns

Design APIs that developers love to use. Learn REST principles, versioning strategies, error handling, and documentation best practices.

Deep Dives into Key Areas

๐Ÿ—๏ธ

System Architecture

Design patterns and architectural decisions

12 Articles
โ˜๏ธ

Cloud Computing

AWS, Azure, and cloud-native development

8 Articles
โšก

Performance

Optimization and scalability techniques

6 Articles
๐Ÿค–

AI & Machine Learning

Practical AI applications in enterprise

5 Articles
๐Ÿ”’

Security

Best practices and compliance

7 Articles
๐Ÿ“ฑ

Modern Frontend

Angular, React, and UI/UX best practices

10 Articles

Have a Project in Mind?

Let's turn your ideas into reality. Schedule a free consultation to discuss how we can help transform your business.