类型计算的方式
条件类型
条件类型帮助我们描述输入类型和输出类型之间的关系,语法类似于 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; }