Skip to content

类型计算的方式

条件类型

条件类型帮助我们描述输入类型和输出类型之间的关系,语法类似于 JavaScript 的条件表达式:

typescript
type IsString<T> = T extends string ? true : false;

// 使用示例
type A = IsString<string>; // true
type B = IsString<number>; // false

分布式条件类型

当条件类型作用于泛型类型时,如果传入的是联合类型,则会变成分布式的:

typescript
type ToArray<T> = T extends any ? T[] : never;
type StrOrNum = ToArray<string | number>; // string[] | number[]

映射类型

映射类型允许我们基于旧类型创建新类型:

typescript
type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

// 使用示例
interface Todo {
  title: string;
  description: string;
}

type ReadonlyTodo = Readonly<Todo>;

内置工具类型

TypeScript 提供了多个实用的内置类型:

Partial

将类型的所有属性变为可选:

typescript
type PartialTodo = Partial<Todo>; // { title?: string; description?: string; }

Required

将类型的所有属性变为必选:

typescript
type RequiredTodo = Required<PartialTodo>; // { title: string; description: string; }

Readonly

将类型的所有属性变为只读:

typescript
type ReadonlyTodo = Readonly<Todo>; // { readonly title: string; readonly description: string; }

// 使用示例
const todo: ReadonlyTodo = {
  title: '学习 TypeScript',
  description: '学习类型系统',
};

// 以下操作将报错
// todo.title = "新标题"; // Error: Cannot assign to 'title' because it is a read-only property

Pick

从类型中选择部分属性:

typescript
type TodoTitle = Pick<Todo, 'title'>; // { title: string; }

Omit

从类型中移除指定的属性:

typescript
// 从 Todo 类型中移除 description 属性
type TodoWithoutDescription = Omit<Todo, 'description'>; // { title: string; }

// 可以同时移除多个属性
interface User {
  id: number;
  name: string;
  email: string;
  password: string;
}

type PublicUser = Omit<User, 'password' | 'email'>; // { id: number; name: string; }

Record

创建一个属性键为 K,属性值为 T 的类型:

typescript
type TodoMap = Record<string, Todo>;

Exclude

从 T 中排除可以赋值给 U 的类型:

typescript
type T0 = Exclude<'a' | 'b' | 'c', 'a'>; // "b" | "c"

Include

从联合类型中包含指定的类型:

typescript
type T0 = Include<string | number | boolean, string | number>; // string | number

// 使用示例
type AllowedTypes = 'photo' | 'video' | 'audio' | 'text';
type MediaTypes = Include<AllowedTypes, 'photo' | 'video'>; // 'photo' | 'video'

Extract

提取 T 中可以赋值给 U 的类型:

typescript
type T1 = Extract<'a' | 'b' | 'c', 'a' | 'f'>; // "a"

实践示例

typescript
// 组合使用示例
interface API {
  user: {
    name: string;
    age: number;
  };
  posts: {
    id: number;
    title: string;
    content: string;
  };
}

// 获取某个 API 路径的请求参数类型
type APIPath = keyof API;
type GetAPIResponse<T extends APIPath> = API[T];

// 使用示例
type UserResponse = GetAPIResponse<'user'>; // { name: string; age: number; }