TypeScript provides several utility types to facilitate common type transformations. These utilities are available globally.

TypeScript 内置了一些功能类型来更容易对普通类型的转换,可以全局使用。

Partial

作用:让所有类型都变成可选
origin code

  1. /**
  2. * Make all properties in T optional
  3. */
  4. type Partial<T> = {
  5. [P in keyof T]?: T[P];
  6. };

Mapped Types:映射类型是一种泛型类型,它使用PropertyKeys的联合(通常keyof创建)来迭代键以创建类型

  1. type OptionsFlags<Type> = {
  2. [Property in keyof Type]: boolean;
  3. };

源码的实现就是使用映射类型创建每一个属性,然后将T中的每个属性变为可选

eample

  1. interface partialObj {
  2. name: string
  3. age: number | string
  4. infoMyself: string
  5. }
  6. function undateObj(person: Partial<partialObj>) {
  7. return person
  8. }
  9. const obj = undateObj({ // Success
  10. name: '老王',
  11. age: '问就是18',
  12. })

Requirec

作用:让所有类型都变成必需,与Partial相反
origin code

  1. /**
  2. * Make all properties in T required
  3. */
  4. type Required<T> = {
  5. [P in keyof T]-?: T[P];
  6. };

eample

  1. interface Props {
  2. a?: number;
  3. b?: string;
  4. }
  5. const obj: Props = { a: 5 };
  6. const obj2: Required<Props> = { a: 5 };
  7. //Error Property 'b' is missing in type '{ a: number; }' but required in type 'Required<Props>'.

Readonly

作用:让T中的每一个属性都变为可读,不可再重新分配
origin code:

  1. /**
  2. * Make all properties in T readonly
  3. */
  4. type Readonly<T> = {
  5. readonly [P in keyof T]: T[P];
  6. };

在Mapped types 上添加关键字readonly,

example:

  1. interface Todo {
  2. title: string;
  3. }
  4. const todo: Readonly<Todo> = {
  5. title: "Delete inactive users",
  6. };
  7. todo.title = "Hello";
  8. //Error Cannot assign to 'title' because it is a read-only property.

Record

origin code:

  1. /**
  2. * Construct a type with a set of properties K of type T
  3. */
  4. type Record<K extends keyof any, T> = {
  5. [P in K]: T;
  6. };

将K中的每个属性([P in K]),都转为T类型

example

  1. interface CatInfo {
  2. age: number;
  3. breed: string;
  4. }
  5. type CatName = "miffy" | "boris" | "mordred";
  6. const cats: Record<CatName, CatInfo> = {
  7. miffy: { age: 10, breed: "Persian" },
  8. boris: { age: 5, breed: "Maine Coon" },
  9. mordred: { age: 16, breed: "British Shorthair" },
  10. };

例子中CatName中的每一个属性都变成了CatInfo类型

Pick

origin code:

  1. /**
  2. * From T, pick a set of properties whose keys are in the union K
  3. */
  4. type Pick<T, K extends keyof T> = {
  5. [P in K]: T[P];
  6. };

通过从T中选取一组属性Keys来构造类型Type。 K extends keyof T 表示K中的每一个属性都来自T
example:

  1. interface Todo {
  2. title: string
  3. description: string
  4. completed: boolean
  5. }
  6. type TodoPreview = Pick<Todo, 'title' | 'completed'>
  7. const todo: TodoPreview = {
  8. title: 'Clean room',
  9. completed: false,
  10. }
  11. /**
  12. * interface TodoPreview {
  13. description: string
  14. completed: boolean
  15. }
  16. */

Exclude

origin code
从 T 中排除那些可分配给 U 的类型

  1. /**
  2. * Exclude from T those types that are assignable to U
  3. */
  4. type Exclude<T, U> = T extends U ? never : T;

T extends U ? never : T 可理解为T是否是U的派生类 是的话则never,不是则为T
never:表示永远不存在的值的类型。
类似(a + b) * c => ac + bc

example

  1. type T0 = Exclude<"a" | "b" | "c", "a">;
  2. type T0 = "b" | "c"
  3. //相当于 <"a","a"> | <"b","a"> | <"c","a">
  4. type T1 = Exclude<"a" | "b" | "c", "a" | "b">;
  5. type T1 = "c"
  6. type T2 = Exclude<string | number | (() => void), Function>;
  7. type T2 = string | number

complex example

  1. // 比如后端接口定义好的返回类型是这个,但是我们并不能直接修改
  2. interface Api {
  3. name: string
  4. age: number
  5. content: string
  6. }
  7. // error: Types of property 'name' are incompatible.
  8. interface CustomApi extends Api {
  9. name: number;
  10. }
  11. // change
  12. interface CustomApi1 extends Pick<Api, 'age'> {
  13. name: number;
  14. }
  15. // 但是上面还是太复杂了,你需要把所有属性挑拣起来,结合 Exclude 将key全拿出来 可以省事很多
  16. interface CustomApi2 extends Pick<Api, Exclude<keyof Api, 'name'>> {
  17. name: number;
  18. }
  19. // Error 类型“{ name: number; }”缺少类型“CustomApi2”中的以下属性: age, content
  20. const api2: CustomApi2 = {
  21. name: 2,
  22. }

Extract

origin code
通过从Type可分配给 的所有联合成员中提取来构造一个类型Union。

  1. /**
  2. * Extract from T those types that are assignable to U
  3. */
  4. type Extract<T, U> = T extends U ? T : never;

取T和U的交集

example:

  1. type union = Extract<'a' | 'b' | 'c' | 'd', 'b' | 'f'>f
  2. // union = 'b'

Omit

origin code

  1. /**
  2. * Construct a type with the properties of T except for those in type K.
  3. 构造一个除类型K之外的T属性的类型
  4. */
  5. type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

example

  1. interface Todo {
  2. title: string;
  3. description: string;
  4. completed: boolean;
  5. createdAt: number;
  6. }
  7. type TodoPreview = Omit<Todo, "description">;
  8. const todo: TodoPreview = {
  9. title: "Clean room",
  10. completed: false,
  11. createdAt: 1615544252770,
  12. };
  13. todo;
  14. const todo: TodoPreview
  15. type TodoInfo = Omit<Todo, "completed" | "createdAt">;
  16. const todoInfo: TodoInfo = {
  17. title: "Pick up kids",
  18. description: "Kindergarten closes at 5pm",
  19. };

NonNullable

origin code
从T中排除null和undefined并重新构造一个类型

  1. /**
  2. * Exclude null and undefined from T
  3. */
  4. type NonNullable<T> = T extends null | undefined ? never : T;

example

  1. type T0 = NonNullable<string | number | undefined>;
  2. //type T0 = string | number

complex example

  1. //若想要接口中每个属性都去除 null | undefined
  2. interface info {
  3. name?:string | null
  4. age?: number | null
  5. }
  6. type enableNonNullable<T> = {
  7. [P in keyof T]-?: NonNullable<T[P]>
  8. }