💻 Programming

Advanced TypeScript Patterns

Last updated: 2025-09-25 12:47:03

Advanced TypeScript

Master advanced TypeScript features including generics, utility types, and advanced type patterns for robust applications.

Generic Types and Constraints

// Generic interfaces
interface Repository {
  findById(id: string): Promise;
  findAll(): Promise;
  create(item: Omit): Promise;
  update(id: string, updates: Partial): Promise;
  delete(id: string): Promise;
}

// Generic constraints
interface Identifiable {
  id: string;
}

class BaseRepository implements Repository {
  constructor(private items: T[] = []) {}
  
  async findById(id: string): Promise {
    return this.items.find(item => item.id === id) || null;
  }
  
  async findAll(): Promise {
    return [...this.items];
  }
  
  async create(item: Omit): Promise {
    const newItem = { ...item, id: crypto.randomUUID() } as T;
    this.items.push(newItem);
    return newItem;
  }
  
  async update(id: string, updates: Partial): Promise {
    const index = this.items.findIndex(item => item.id === id);
    if (index === -1) throw new Error('Item not found');
    
    this.items[index] = { ...this.items[index], ...updates };
    return this.items[index];
  }
  
  async delete(id: string): Promise {
    const index = this.items.findIndex(item => item.id === id);
    if (index === -1) return false;
    
    this.items.splice(index, 1);
    return true;
  }
}

Utility Types and Mapped Types

// Built-in utility types
type User = {
  id: string;
  name: string;
  email: string;
  password: string;
  createdAt: Date;
};

type CreateUserRequest = Omit;
type UpdateUserRequest = Partial>;
type PublicUser = Omit;
type UserEmail = Pick;

// Custom mapped types
type Optional = Omit & Partial>;
type RequiredFields = T & Required>;

// Make specific fields optional
type CreateUserOptional = Optional;

// Make specific fields required
type UserWithRequiredEmail = RequiredFields, 'email'>;

// Advanced mapped types
type Nullable = {
  [P in keyof T]: T[P] | null;
};

type DeepReadonly = {
  readonly [P in keyof T]: T[P] extends object ? DeepReadonly : T[P];
};

Conditional Types and Template Literals

// Conditional types
type ApiResponse = T extends string
  ? { message: T }
  : T extends number
  ? { code: T }
  : { data: T };

type StringResponse = ApiResponse; // { message: string }
type NumberResponse = ApiResponse; // { code: number }
type ObjectResponse = ApiResponse; // { data: User }

// Template literal types
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type ApiEndpoint = 'users' | 'posts' | 'comments';
type ApiRoute = `/${ApiEndpoint}`;
type ApiRouteWithMethod = `${HttpMethod} ${ApiRoute}`;

// Route parameter extraction
type ExtractParams = T extends `${string}/:${infer Param}/${infer Rest}`
  ? { [K in Param]: string } & ExtractParams<`/${Rest}`>
  : T extends `${string}/:${infer Param}`
  ? { [K in Param]: string }
  : {};

type UserRoute = ExtractParams<'/users/:id'>; // { id: string }
type PostRoute = ExtractParams<'/users/:userId/posts/:postId'>; // { userId: string, postId: string }

Decorators and Metadata

// Class decorators
function Entity(tableName: string) {
  return function {}>(constructor: T) {
    return class extends constructor {
      static tableName = tableName;
    };
  };
}

// Property decorators
function Column(options?: { name?: string; type?: string }) {
  return function(target: any, propertyKey: string) {
    const columns = Reflect.getMetadata('columns', target) || [];
    columns.push({
      property: propertyKey,
      column: options?.name || propertyKey,
      type: options?.type || 'varchar'
    });
    Reflect.defineMetadata('columns', columns, target);
  };
}

// Method decorators
function Validate(schema: any) {
  return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    
    descriptor.value = function(...args: any[]) {
      // Validation logic here
      console.log(`Validating ${propertyKey} with schema:`, schema);
      return originalMethod.apply(this, args);
    };
  };
}

// Usage
@Entity('users')
class User {
  @Column({ name: 'user_id', type: 'uuid' })
  id: string;
  
  @Column()
  name: string;
  
  @Column()
  email: string;
  
  @Validate({ email: 'required|email', name: 'required|string' })
  create(data: CreateUserRequest) {
    // Create user logic
  }
}