学习了泛型的基础知识后,本篇通过实际案例展示泛型在真实项目中的应用。
通用 API 响应处理#
// TypeScript 5.x
// 通用响应类型interface ApiResponse<T> { code: number message: string data: T timestamp: number}
// 分页响应interface PaginatedData<T> { items: T[] total: number page: number pageSize: number hasMore: boolean}
// 通用请求函数async function request<T>( url: string, options?: RequestInit): Promise<ApiResponse<T>> { const response = await fetch(url, options) return response.json()}
// 使用interface User { id: number name: string email: string}
const userResponse = await request<User>('/api/user/1')console.log(userResponse.data.name) // 类型安全
const usersResponse = await request<PaginatedData<User>>('/api/users')console.log(usersResponse.data.items[0].name) // 类型安全状态管理#
// 通用状态管理器class Store<S extends object> { private state: S private listeners: Set<(state: S) => void> = new Set()
constructor(initialState: S) { this.state = initialState }
getState(): Readonly<S> { return this.state }
setState<K extends keyof S>(key: K, value: S[K]): void setState(partial: Partial<S>): void setState<K extends keyof S>( keyOrPartial: K | Partial<S>, value?: S[K] ): void { if (typeof keyOrPartial === 'string') { this.state = { ...this.state, [keyOrPartial]: value } } else { this.state = { ...this.state, ...keyOrPartial } } this.notify() }
subscribe(listener: (state: S) => void): () => void { this.listeners.add(listener) return () => this.listeners.delete(listener) }
private notify(): void { this.listeners.forEach((l) => l(this.state)) }}
// 使用interface AppState { user: { name: string } | null theme: 'light' | 'dark' loading: boolean}
const store = new Store<AppState>({ user: null, theme: 'light', loading: false,})
store.setState('loading', true)store.setState({ user: { name: '张三' } })表单处理#
// 表单字段类型interface FormField<T> { value: T error?: string touched: boolean validate(): boolean}
// 表单类型type FormFields<T> = { [K in keyof T]: FormField<T[K]>}
// 表单管理器class FormManager<T extends object> { private fields: FormFields<T> private validators: Partial< Record<keyof T, (value: any) => string | undefined> >
constructor( initialValues: T, validators?: Partial<Record<keyof T, (value: any) => string | undefined>> ) { this.validators = validators || {} this.fields = {} as FormFields<T>
for (const key in initialValues) { this.fields[key] = { value: initialValues[key], touched: false, validate: () => this.validateField(key), } } }
private validateField(key: keyof T): boolean { const validator = this.validators[key] if (validator) { const error = validator(this.fields[key].value) this.fields[key].error = error return !error } return true }
setValue<K extends keyof T>(key: K, value: T[K]): void { this.fields[key].value = value this.fields[key].touched = true this.validateField(key) }
getValues(): T { const values = {} as T for (const key in this.fields) { values[key] = this.fields[key].value } return values }
isValid(): boolean { return Object.keys(this.fields).every((key) => this.validateField(key as keyof T) ) }}
// 使用interface LoginForm { email: string password: string}
const form = new FormManager<LoginForm>( { email: '', password: '' }, { email: (v) => (!v.includes('@') ? '无效的邮箱' : undefined), password: (v) => (v.length < 6 ? '密码至少6位' : undefined), })
form.setValue('email', 'test@test.com')form.setValue('password', '123456')console.log(form.isValid()) // true事件系统#
type EventHandler<T> = (payload: T) => void
class EventEmitter<EventMap extends Record<string, any>> { private handlers = new Map<keyof EventMap, Set<Function>>()
on<K extends keyof EventMap>( event: K, handler: EventHandler<EventMap[K]> ): () => void { if (!this.handlers.has(event)) { this.handlers.set(event, new Set()) } this.handlers.get(event)!.add(handler) return () => this.off(event, handler) }
off<K extends keyof EventMap>( event: K, handler: EventHandler<EventMap[K]> ): void { this.handlers.get(event)?.delete(handler) }
emit<K extends keyof EventMap>(event: K, payload: EventMap[K]): void { this.handlers.get(event)?.forEach((handler) => handler(payload)) }
once<K extends keyof EventMap>( event: K, handler: EventHandler<EventMap[K]> ): void { const wrapper: EventHandler<EventMap[K]> = (payload) => { handler(payload) this.off(event, wrapper) } this.on(event, wrapper) }}
// 使用interface AppEvents { 'login': { userId: string; timestamp: number } 'logout': undefined 'error': Error 'data:update': { type: string; data: unknown }}
const emitter = new EventEmitter<AppEvents>()
emitter.on('login', ({ userId, timestamp }) => { console.log(`User ${userId} logged in at ${timestamp}`)})
emitter.emit('login', { userId: '123', timestamp: Date.now() })依赖注入容器#
type Constructor<T = any> = new (...args: any[]) => T
class Container { private instances = new Map<Constructor, any>() private factories = new Map<Constructor, () => any>()
register<T>(ctor: Constructor<T>, factory: () => T): void { this.factories.set(ctor, factory) }
registerSingleton<T>(ctor: Constructor<T>, factory: () => T): void { this.factories.set(ctor, () => { if (!this.instances.has(ctor)) { this.instances.set(ctor, factory()) } return this.instances.get(ctor) }) }
resolve<T>(ctor: Constructor<T>): T { const factory = this.factories.get(ctor) if (!factory) { throw new Error(`No registration for ${ctor.name}`) } return factory() }}
// 使用interface Logger { log(message: string): void}
class ConsoleLogger implements Logger { log(message: string) { console.log(message) }}
class UserService { constructor(private logger: Logger) {}
createUser(name: string) { this.logger.log(`Creating user: ${name}`) }}
const container = new Container()container.registerSingleton(ConsoleLogger, () => new ConsoleLogger())container.register( UserService, () => new UserService(container.resolve(ConsoleLogger)))
const userService = container.resolve(UserService)userService.createUser('张三')类型安全的路由#
// 路由定义type RouteParams<T extends string> = T extends `${string}:${infer Param}/${infer Rest}` ? { [K in Param | keyof RouteParams<Rest>]: string } : T extends `${string}:${infer Param}` ? { [K in Param]: string } : {}
// 路由器class Router<Routes extends Record<string, string>> { private routes = new Map<keyof Routes, Function>()
register<K extends keyof Routes>( path: K, handler: (params: RouteParams<Routes[K] & string>) => void ): void { this.routes.set(path, handler) }
navigate<K extends keyof Routes>( path: K, params: RouteParams<Routes[K] & string> ): void { const handler = this.routes.get(path) if (handler) { handler(params) } }}
// 使用type AppRoutes = { home: '/' user: '/user/:id' post: '/post/:postId/comment/:commentId'}
const router = new Router<AppRoutes>()
router.register('user', (params) => { console.log(`User ID: ${params.id}`) // 类型安全})
router.register('post', (params) => { console.log(`Post: ${params.postId}, Comment: ${params.commentId}`)})
router.navigate('user', { id: '123' })常见问题#
🙋 泛型会增加运行时开销吗?#
不会。泛型只在编译时存在,编译后的 JavaScript 没有类型信息。
🙋 如何调试复杂的泛型类型?#
使用类型别名展开:
// 复杂类型type Complex<T> = T extends object ? { [K in keyof T]: Complex<T[K]> } : T
// 调试:创建具体实例查看类型type Debug = Complex<{ a: { b: string } }>// 鼠标悬停查看展开后的类型总结#
泛型的实战应用场景:
- API 响应封装
- 状态管理
- 表单处理
- 事件系统
- 依赖注入
- 路由系统
下一篇我们将进入类型系统进阶,学习类型守卫。