Appearance
TypeScript 高级技巧与实战
TypeScript 作为 JavaScript 的超集,提供了强大的类型系统和丰富的高级特性。本文将深入探讨一些实用的高级技巧,帮助你写出更优雅、更安全的代码。
1. 高级类型操作
条件类型(Conditional Types)
条件类型允许我们根据类型条件来选择不同的类型:
typescript
type NonNullable<T> = T extends null | undefined ? never : T
// 实用示例:API 响应类型处理
type ApiResponse<T> = T extends string
? { message: T }
: T extends object
? { data: T }
: { value: T }
type StringResponse = ApiResponse<string> // { message: string }
type ObjectResponse = ApiResponse<{ id: number }> // { data: { id: number } }
映射类型(Mapped Types)
映射类型可以基于现有类型创建新类型:
typescript
// 深度只读
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P]
}
// 可选属性转必需
type RequiredKeys<T, K extends keyof T> = T & Required<Pick<T, K>>
interface User {
id?: number
name?: string
email?: string
}
type UserWithRequiredEmail = RequiredKeys<User, 'email'>
// { id?: number; name?: string; email: string }
2. 模板字面量类型
模板字面量类型提供了强大的字符串操作能力:
typescript
// 事件名称生成
type EventName<T extends string> = `on${Capitalize<T>}`
type ClickEvent = EventName<'click'> // 'onClick'
// 路由类型安全
type Route = '/users' | '/posts' | '/settings'
type ApiEndpoint<T extends Route> = `https://api.example.com${T}`
type UserEndpoint = ApiEndpoint<'/users'> // 'https://api.example.com/users'
// CSS 属性类型
type CSSProperty = 'margin' | 'padding' | 'border'
type CSSDirection = 'top' | 'right' | 'bottom' | 'left'
type CSSPropertyWithDirection = `${CSSProperty}-${CSSDirection}`
// 'margin-top' | 'margin-right' | ... | 'border-left'
3. 高级泛型技巧
泛型约束与推断
typescript
// 键值对提取
function pick<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {
const result = {} as Pick<T, K>
keys.forEach(key => {
result[key] = obj[key]
})
return result
}
// 函数参数推断
type Parameters<T extends (...args: any) => any> = T extends (
...args: infer P
) => any
? P
: never
type ReturnType<T extends (...args: any) => any> = T extends (
...args: any
) => infer R
? R
: any
// 实用示例
function createApiClient<T extends Record<string, (...args: any[]) => any>>(
endpoints: T
): {
[K in keyof T]: (
...args: Parameters<T[K]>
) => Promise<ReturnType<T[K]>>
} {
// 实现省略
return {} as any
}
4. 类型守卫与断言
自定义类型守卫
typescript
// 基础类型守卫
function isString(value: unknown): value is string {
return typeof value === 'string'
}
function isNumber(value: unknown): value is number {
return typeof value === 'number' && !isNaN(value)
}
// 对象类型守卫
interface User {
id: number
name: string
email: string
}
function isUser(obj: unknown): obj is User {
return (
typeof obj === 'object' &&
obj !== null &&
'id' in obj &&
'name' in obj &&
'email' in obj &&
typeof (obj as User).id === 'number' &&
typeof (obj as User).name === 'string' &&
typeof (obj as User).email === 'string'
)
}
// 泛型类型守卫
function hasProperty<T, K extends PropertyKey>(
obj: T,
key: K
): obj is T & Record<K, unknown> {
return typeof obj === 'object' && obj !== null && key in obj
}
5. 装饰器与元数据
类装饰器
typescript
// 日志装饰器
function Logger<T extends { new (...args: any[]): {} }>(constructor: T) {
return class extends constructor {
constructor(...args: any[]) {
super(...args)
console.log(`Creating instance of ${constructor.name}`)
}
}
}
// 方法装饰器
function Measure(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value
descriptor.value = function (...args: any[]) {
const start = performance.now()
const result = originalMethod.apply(this, args)
const end = performance.now()
console.log(`${propertyKey} took ${end - start} milliseconds`)
return result
}
}
@Logger
class ApiService {
@Measure
async fetchData(url: string): Promise<any> {
// 实现省略
return fetch(url).then(res => res.json())
}
}
6. 实战应用场景
状态管理类型安全
typescript
// Redux 风格的状态管理
interface AppState {
user: User | null
posts: Post[]
loading: boolean
}
type ActionType = 'SET_USER' | 'SET_POSTS' | 'SET_LOADING'
interface Action<T extends ActionType, P = any> {
type: T
payload: P
}
type SetUserAction = Action<'SET_USER', User | null>
type SetPostsAction = Action<'SET_POSTS', Post[]>
type SetLoadingAction = Action<'SET_LOADING', boolean>
type AppAction = SetUserAction | SetPostsAction | SetLoadingAction
// 类型安全的 reducer
function appReducer(state: AppState, action: AppAction): AppState {
switch (action.type) {
case 'SET_USER':
return { ...state, user: action.payload } // payload 自动推断为 User | null
case 'SET_POSTS':
return { ...state, posts: action.payload } // payload 自动推断为 Post[]
case 'SET_LOADING':
return { ...state, loading: action.payload } // payload 自动推断为 boolean
default:
return state
}
}
API 客户端类型安全
typescript
// API 端点定义
interface ApiEndpoints {
'/users': {
GET: { response: User[] }
POST: { body: Omit<User, 'id'>; response: User }
}
'/users/:id': {
GET: { params: { id: string }; response: User }
PUT: { params: { id: string }; body: Partial<User>; response: User }
DELETE: { params: { id: string }; response: void }
}
}
// 类型安全的 API 客户端
class TypedApiClient {
async request<
Path extends keyof ApiEndpoints,
Method extends keyof ApiEndpoints[Path]
>(
path: Path,
method: Method,
options?: ApiEndpoints[Path][Method] extends { params: infer P }
? { params: P } & (ApiEndpoints[Path][Method] extends { body: infer B }
? { body: B }
: {})
: ApiEndpoints[Path][Method] extends { body: infer B }
? { body: B }
: {}
): Promise<
ApiEndpoints[Path][Method] extends { response: infer R } ? R : never
> {
// 实现省略
return {} as any
}
}
// 使用示例
const api = new TypedApiClient()
// 类型安全的 API 调用
const users = await api.request('/users', 'GET') // 返回 User[]
const user = await api.request('/users/:id', 'GET', { params: { id: '1' } }) // 返回 User
const newUser = await api.request('/users', 'POST', {
body: { name: 'John', email: 'john@example.com' }
}) // 返回 User
7. 性能优化技巧
类型计算优化
typescript
// 避免深度递归类型
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P]
}
// 使用分布式条件类型
type Flatten<T> = T extends (infer U)[] ? U : T
// 缓存复杂类型计算
type CachedComplexType<T> = T extends string
? StringResult
: T extends number
? NumberResult
: DefaultResult
interface StringResult { type: 'string' }
interface NumberResult { type: 'number' }
interface DefaultResult { type: 'default' }
总结
TypeScript 的高级特性为我们提供了强大的类型安全保障和开发体验。通过合理使用这些技巧,我们可以:
- 提高代码质量:通过类型系统捕获潜在错误
- 增强开发体验:获得更好的 IDE 支持和自动补全
- 改善代码维护性:类型作为文档,提高代码可读性
- 优化性能:编译时类型检查,运行时零开销
掌握这些高级技巧,将让你在 TypeScript 开发中更加得心应手,写出更加优雅和安全的代码。