TypeScript 类型系统的强大之处
TypeScript 的类型系统不仅能提供类型检查,还能实现强大的类型编程。本文深入探索 TypeScript 的高级类型特性。
1. 泛型约束
使用 extends 限制泛型类型:
// 基础泛型约束
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
const user = { name: 'John', age: 30 };
const name = getProperty(user, 'name'); // ✅
const invalid = getProperty(user, 'email'); // ❌ Error
// 多重约束
interface Lengthwise {
length: number;
}
function logLength<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}2. 条件类型
根据条件选择类型:
// 基础条件类型
type IsString<T> = T extends string ? true : false;
type A = IsString<string>; // true
type B = IsString<number>; // false
// 实用条件类型
type NonNullable<T> = T extends null | undefined ? never : T;
type User = { name: string; age?: number };
type RequiredUser = NonNullable<User>;
// 分布式条件类型
type ToArray<T> = T extends any ? T[] : never;
type StrOrNumArray = ToArray<string | number>;
// string[] | number[]3. 映射类型
转换对象类型的属性:
// Partial - 所有属性可选
type Partial<T> = {
[P in keyof T]?: T[P];
};
// Required - 所有属性必填
type Required<T> = {
[P in keyof T]-?: T[P];
};
// Readonly - 所有属性只读
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
// Pick - 选择特定属性
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
interface User {
id: number;
name: string;
email: string;
age: number;
}
type UserPreview = Pick<User, 'id' | 'name'>;
// { id: number; name: string; }4. 模板字面量类型
操作字符串类型:
// 字符串拼接
type EmailAddress<T extends string> = `${T}@example.com`;
type MyEmail = EmailAddress<'john'>; // 'john@example.com'
// 事件名称生成
type EventName<T extends string> = `on${Capitalize<T>}`;
type ClickEvent = EventName<'click'>; // 'onClick'
// CSS 属性
type CSSProperty =
| 'color'
| 'background'
| 'padding';
type CSSValue<P extends CSSProperty> =
P extends 'color' ? string :
P extends 'background' ? string :
P extends 'padding' ? number :
never;5. infer 关键字
在条件类型中推断类型:
// 提取函数返回类型
type ReturnType<T> =
T extends (...args: any[]) => infer R ? R : never;
function getUser() {
return { name: 'John', age: 30 };
}
type User = ReturnType<typeof getUser>;
// { name: string; age: number; }
// 提取 Promise 类型
type Unpromise<T> =
T extends Promise<infer R> ? R : T;
type Result = Unpromise<Promise<string>>; // string
// 提取数组元素类型
type ArrayElement<T> =
T extends (infer E)[] ? E : T;
type Item = ArrayElement<string[]>; // string6. 递归类型
定义递归数据结构:
// 深度只读
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object
? DeepReadonly<T[P]>
: T[P];
};
// 深度可选
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object
? DeepPartial<T[P]>
: T[P];
};
// 路径类型
type PathOf<T> = {
[K in keyof T]: K extends string
? T[K] extends object
? K | `${K}.${PathOf<T[K]>}`
: K
: never;
}[keyof T];7. 实用类型工具
构建可复用的类型工具:
// 提取可选属性
type OptionalKeys<T> = {
[K in keyof T]-?: {} extends Pick<T, K> ? K : never
}[keyof T];
// 提取必填属性
type RequiredKeys<T> = {
[K in keyof T]-?: {} extends Pick<T, K> ? never : K
}[keyof T];
// 函数重载类型
type Overload<T> = T extends {
(...args: infer A1): infer R1;
(...args: infer A2): infer R2;
}
? ((...args: A1) => R1) | ((...args: A2) => R2)
: never;8. 类型保护
运行时类型检查:
// 自定义类型保护
function isString(value: unknown): value is string {
return typeof value === 'string';
}
// 判别联合类型
type Shape =
| { kind: 'circle'; radius: number }
| { kind: 'rectangle'; width: number; height: number };
function getArea(shape: Shape) {
switch (shape.kind) {
case 'circle':
return Math.PI * shape.radius ** 2;
case 'rectangle':
return shape.width * shape.height;
}
}实战案例
构建类型安全的表单库:
type FormValues<T> = {
[K in keyof T]: T[K] extends object
? FormValues<T[K]>
: T[K];
};
type FormErrors<T> = {
[K in keyof T]?: T[K] extends object
? FormErrors<T[K]>
: string;
};
interface UseForm<T> {
values: FormValues<T>;
errors: FormErrors<T>;
handleChange: <K extends keyof T>(field: K, value: T[K]) => void;
}总结
TypeScript 的高级类型系统非常强大,掌握这些技巧能让你编写更安全、更可维护的代码。持续实践是掌握这些特性的关键。