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[]>; // string

6. 递归类型

定义递归数据结构:

// 深度只读
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 的高级类型系统非常强大,掌握这些技巧能让你编写更安全、更可维护的代码。持续实践是掌握这些特性的关键。