Skip to content
On this page

类型体操

00004-easy-pick

实现 TS 内置的 Pick<T, K>

ts
type MyPick<T, K extends keyof T> = {
  [P in K]: T[P];
};
type MyPick<T, K extends keyof T> = {
  [P in K]: T[P];
};
ts
interface Todo {
  title: string;
  description: string;
  completed: boolean;
}

type TodoExcludeCompleted = MyPick<Todo, "title" | "description">;
interface Todo {
  title: string;
  description: string;
  completed: boolean;
}

type TodoExcludeCompleted = MyPick<Todo, "title" | "description">;

关键点:

  • keyof 关键字会将对象类型 T 的属性 Key 全部收集起来,组成一个联合类型
  • [P in K] TS 中的对象类型的遍历

00007-easy-readonly

实现内置的 Readonly<T>,给每个属性都添加 readonly

ts
type MyReadonly<T> = {
  readonly [K in keyof T]: T[K];
};
type MyReadonly<T> = {
  readonly [K in keyof T]: T[K];
};
ts
interface Todo {
  title: string;
  description: string;
  completed: boolean;
  meta: {
    author: string;
  };
}

type ReadonlyTodo = MyReadonly<Todo>;
interface Todo {
  title: string;
  description: string;
  completed: boolean;
  meta: {
    author: string;
  };
}

type ReadonlyTodo = MyReadonly<Todo>;

关键点:

  • 在对象类型的便利前面加个 readonly 关键字

00011-easy-tuple-to-object

会传入一个元组类型,将这个元组类型转换为对象类型。这个对象类型的键/值都是从元组中遍历出来

ts
type TuppleToObject<T extends readonly (string | number | symbol)[]> = {
  [key in T[number]]: key;
};
type TuppleToObject<T extends readonly (string | number | symbol)[]> = {
  [key in T[number]]: key;
};
ts
const tuple = ["tesla", "model 3", "model X", "model Y"] as const;

const tupleToObject: TupleToObject<typeof tuple> = {
  tesla: "tesla",
  "model 3": "model 3",
  "model X": "model X",
  "model Y": "model Y",
};
const tuple = ["tesla", "model 3", "model X", "model Y"] as const;

const tupleToObject: TupleToObject<typeof tuple> = {
  tesla: "tesla",
  "model 3": "model 3",
  "model X": "model X",
  "model Y": "model Y",
};

关键点:

  • 如果去遍历一个数字类型/元组类型: [key in T[number]]

00014-easy-first

实现一个通用First<T>,它接受一个数组 T 并返回它的第一个元素的类型

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

关键点:

  • TS 类型的三元表达式:T extends Type ? Type1 : Type2;

00018-easy-tuple-length

创建一个通用的 Length,接受一个 readonly 的数组,返回这个数组的长度

ts
type Length<T extends readonly any[]> = T["length"];
type Length<T extends readonly any[]> = T["length"];
ts
const tesla = ["tesla", "model 3", "model X", "model Y"] as const;

type LengthTesla = Length<typeof tesla>;
const tesla = ["tesla", "model 3", "model X", "model Y"] as const;

type LengthTesla = Length<typeof tesla>;

关键点:

  • 在 TS 中获取数组类型的长度方式: T["length"]

00043-easy-exclude

实现内置的Exclude <T, U>类型,从联合类型 T 中排除 U 的类型成员,来构造一个新的类型

ts
type MyExclude<T, U> = T extends U ? never : T;
type MyExclude<T, U> = T extends U ? never : T;

关键点:

  • 联合类型的遍历: T extends U ? Type1 : Type2 (想象成联合类型的每一个类型都会进一遍这个三元表达式,因此来进行判断)

00189-easy-awaited

假如我们有一个 Promise 对象,这个 Promise 对象会返回一个类型。在 TS 中,我们用 Promise 中的 T 来描述这个 Promise 返回的类型

比如:Promise<ExampleType>,请你返回 ExampleType 类型

ts
type MyAwaited<T extends Promise<unknown>> = T extends Promise<infer X>
  ? X extends Promise<unknown>
    ? MyAwaited<X>
    : X
  : never;

/**
 * 代码解读
 *  1. 我们传给 MyAwaited<T> 的 T 泛型限制了 必须是 Promise 的类型,这样就解决了  type error = MyAwaited<number>; 的爆红问题
 *  2. 在根据 T 限制了必须是 Promise 类型,所以这段代码 T extends Promise<infer X> ? Type1 : Type2  是一定会走 Type1的,因此 Type2 写什么类型都无所谓
 *  3. 进入到 Type1 后,先要理解下 Infer 关键字 在 条件类型 extends 的作用, Infer 是推断的意思,意思就是 假设 Promise<T> 里的泛型的类型 是 X 类型
 *  4. 然后问 X 类型 它是不是也是 Promise 类型 如果是 则进入 MyAwaited<X> 进行递归操作
 *  5. 如果不是Promise类型,则返回这个 X 类型
 */
type MyAwaited<T extends Promise<unknown>> = T extends Promise<infer X>
  ? X extends Promise<unknown>
    ? MyAwaited<X>
    : X
  : never;

/**
 * 代码解读
 *  1. 我们传给 MyAwaited<T> 的 T 泛型限制了 必须是 Promise 的类型,这样就解决了  type error = MyAwaited<number>; 的爆红问题
 *  2. 在根据 T 限制了必须是 Promise 类型,所以这段代码 T extends Promise<infer X> ? Type1 : Type2  是一定会走 Type1的,因此 Type2 写什么类型都无所谓
 *  3. 进入到 Type1 后,先要理解下 Infer 关键字 在 条件类型 extends 的作用, Infer 是推断的意思,意思就是 假设 Promise<T> 里的泛型的类型 是 X 类型
 *  4. 然后问 X 类型 它是不是也是 Promise 类型 如果是 则进入 MyAwaited<X> 进行递归操作
 *  5. 如果不是Promise类型,则返回这个 X 类型
 */

关键点

  • Infer 关键字的理解使用

03312-easy-parameters

实现内置的 Parameters 类型,就是获取 函数泛型 T 回调函数中的 参数类型

ts
type MyParameters<T extends (...args: any[]) => any> = T extends (
  ...args: infer X
) => any
  ? X
  : never;
type MyParameters<T extends (...args: any[]) => any> = T extends (
  ...args: infer X
) => any
  ? X
  : never;

关键点

  • Infer 关键字的理解使用

Released under the MIT License.