TS内置类型实现

2022-4-20 6 min read

TOC

一、映射类型

1、基本使用

语法:{ [p in K]: T }

Partial类型实现:

type Partial<T> = { [P in keyof T]?: T[P] | undefined] };

Readonly类型实现:

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

keyof操作符的作用是将类型 T 的属性名组成联合类型返回,比如类型T 有x,y,z属性,最后返回x | y | z联合类型。

2、重映射

在TS4.1版本中可以使用 as 子句对映射类型的键进行重映射(Key Remapping):

type PartialWithRemap<T> = { [P in keyof T as NewKeyType]: T[P] | undefined }

NewKeyType必须是string | number | symbol的子类型。


使用重映射实现Omit内置类型:

type Omit<T, K extends keyof T> = { [P in keyof T as Exclude<keyof T, K>]: T[P] }

二、条件类型

1. 基本使用

语法:T extends U ? X : Y

Exclude类型实现:

type Exclude<T, U> = T extends U ? never : T

Extract类型实现:

type Extract<T, U> = T extends U ? T : never

NonNullable类型实现:

type NonNullable<T> = T extends null | undefined ? never : T

2. infer推断

对于函数类型想要获取其参数或者 return 的返回类型就要用到 infer 关键字

type Parameters<T> = T extends (...args: infer P) ⇒ any ? P : never

ReturnType类型实现:

type ReturnType<T> = T extends (...args: any) ⇒ infer R ? R : any

3. 分布式条件类型

在条件类型中,如果被检查的类型是一个裸类型参数:没有被数组、元组或 Promise 等包装过,那么该条件类型被称为分布式条件类型。

当分布式条件类型传入的类型是联合类型时,在运算过程中会被分解成多个分支

4. 协变位置和逆变位置

  • 协变:允许子类型赋值给父类型
  • 逆变:允许父类型赋值给子类型
  • 协变位置:函数的返回值位置
  • 逆变位置:函数的参数位置

现在要实现一个获取对象键的类型PropertyType:

type PropertyType<T> = T extends { [key: string]: infer U } ? U : never;

type User = {
  id: number;
  name: string
};

type UserPropertyType = PropertyType<User>; // number | string

此时 U 所处的位置即是协变位置,该位置上同一个类型变量存在多个候选者的话,最终的类型将被推断为联合类型。

下面是一个逆变位置的例子:

type Bar<T> = T extends { a: (x: infer U) => void, b: (x: infer U) => void } ? U : never;

逆变推断为交叉类型。

最后实现一个将联合类型转成交叉类型的类型:

type UnionToIntersection<U> = (U extends any ? (arg: U) => void : never) extends (arg: infer R) => void ? R : never

三、类型实现

1. Equal

type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T> extends Y ? 1 : 2 ? true : false;

2. Pick

type Pick<T, K extends keyof T> = { [P in K]: T[P] };

3. Omit

使用重映射实现 Omit 内置类型:

type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

type Omit<T, K extends keyof T> = { [P in Exclude<keyof T, K>]: T[P] };

4. Readonly

Readonly类型实现:

5. Exclude

Exclude类型实现:

6. Awaited

type Awaited<T> = T extends Promise<infer P> ? P extends Promise<any> ? Awaited<P> : P : error;

7. TupleToObject

type TupleToObject<T extends readonly unknown[]> = { [P in T[number]]: P };

8. First

type First<T extends unknown[]> = T extends [] ? never : T[0];

9. Length of Tuple

type LengthOfTuple<T extends readonly unknown[]> = T['length'];

10. If

type If<C extends boolean, T, F> = C extends true ? T : F;

11. Concat

type Concat<T extends unknown[], U extends unknown[]> = [...T, ...U];

12. Includes

type Includes<T extends readonly any[], U> = T extends [infer H, ... infer R] ? Equal<H, U> extends true ? true: Includes<R, U> : false;

13. Push

type Push<T extends unknown[], U> = [...T, U];

14. Unshift

type Unshift<T extends unknown[], U> = [U, ...T];

15. Parameters

type Parameters = T extends (…args: infer P) ⇒ any ? P : never

16. ReturnType

ReturnType类型实现:

17. Readonly2

type MyReadonly2<T, K extends keyof T = keyof T> = { readonly [P in K]: T[P] } & Omit<T, K>;

18. Deep Readonly

type DeepReadonly<T> = {
	[K in keyof T]: keyof T[K] extends never ? T[K] : DeepReadonly<T[K]>
}

19. Tuple To Union

type TupleToUnion<T extends readonly unknown[]> = T[number];

20. Chain-able

type Chainable<T = {}> = {
	option<K extends string, V>(key: K extends keyof T ? never : K, value: V): Chainable<T & { [P in K]: V };
	get(): T;
}

21. Last of Array

type LastOfArray<T extends unknow[], U> = T extends [...unknown, infer R] : R : never;

22. Pop

type Pop<T extends number[], U> = T extends [...infer H, unknown] ? H : never;

23. PromiseAll

declare function PromiseAll<T extends unknown[]>(values: readonly [...T]): Promise<{ [P in keyof T]: T[P] extends Promise<infer R> ? R : T[P]}>;

24. Lookup

type Lookup<T, U> = T extends { type: U } ? T : never;