💻 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
}
}