超越基础类型
TypeScript的类型系统远比表面上看起来更强大。掌握高级类型技巧能让代码更加安全和优雅。
类型体操
条件类型
根据条件选择不同的类型:
type IsString<T> = T extends string ? true : false;
type Result1 = IsString<"hello">; // true
type Result2 = IsString<42>; // false
映射类型
对已有类型的属性进行变换:
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
type Partial<T> = {
[P in keyof T]?: T[P];
};
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
递归类型
处理嵌套结构的类型:
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};
infer关键字
从类型中提取子类型:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type ArrayItem<T> = T extends (infer U)[] ? U : never;
type PromiseValue<T> = T extends Promise<infer U> ? U : T;
泛型进阶
泛型约束
使用extends约束泛型参数的范围:
interface HasId {
id: number;
}
function getById<T extends HasId>(items: T[], id: number): T | undefined {
return items.find(item => item.id === id);
}
泛型工具类型
TypeScript内置了大量有用的工具类型,需要深入理解其使用场景:
Partial<T>:所有属性变为可选Required<T>:所有属性变为必选Readonly<T>:所有属性变为只读Pick<T, K>:从T中选取部分属性Omit<T, K>:从T中排除部分属性Record<K, V>:构造一个键值类型Exclude<T, U>:从联合类型中排除某些类型
模板字面量类型
TypeScript 4.1+支持的模板字面量类型:
type EventName = `on${Capitalize<string>}`;
type CSSProperty = `--${string}`;
装饰器
类装饰器
修改类的行为和结构:
function LogClass<T extends { new (...args: any[]): {} }>(constructor: T) {
return class extends constructor {
createdAt = new Date();
};
}
方法装饰器
拦截方法调用,实现日志、缓存等功能:
function Log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const original = descriptor.value;
descriptor.value = function(...args: any[]) {
console.log(`Calling ${propertyKey} with`, args);
return original.apply(this, args);
};
}
实践建议
- 优先使用interface定义公共API的类型
- 使用type定义联合类型和工具类型
- 避免过度抽象:复杂的类型体操可能降低代码可读性
- 善用satisfies操作符(TypeScript 4.9+)进行类型验证
- 使用ts-reset等工具库增强类型安全
掌握TypeScript的高级类型系统,能够写出更具表达力和安全性的代码。
