简单

Pick

不使用 Pick<T, K> ,实现 TS 内置的 Pick<T, K> 的功能。 从类型 T 中选出符合 K 的属性,构造一个新的类型。

例如:

interface Todo {
  title: string;
  description: string;
  completed: boolean;
}

type TodoPreview = MyPick<Todo, "title" | "completed">;

const todo: TodoPreview = {
  title: "Clean room",
  completed: false,
};

解答:

type MyPick<T, M extends keyof T> = {
  [p in M]: T[p];
};

对象属性只读

不要使用内置的 Readonly<T>,自己实现一个。

泛型 Readonly<T> 会接收一个 泛型参数,并返回一个完全一样的类型,只是所有属性都会是只读 (readonly) 的。

也就是不可以再对该对象的属性赋值。

例如:

interface Todo {
  title: string;
  description: string;
}

const todo: MyReadonly<Todo> = {
  title: "Hey",
  description: "foobar",
};

todo.title = "Hello"; // Error: cannot reassign a readonly property
todo.description = "barFoo"; // Error: cannot reassign a readonly property

解答

type MyReadonly<T> = {
  readonly [p in keyof T]: T[p];
};

元组转换为对象

将一个元组类型转换为对象类型,这个对象类型的键/值和元组中的元素对应。 例如:

const tuple = ["tesla", "model 3", "model X", "model Y"] as const;

type result = TupleToObject<typeof tuple>; // expected { tesla: 'tesla', 'model 3': 'model 3', 'model X': 'model X', 'model Y': 'model Y'}

解答

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

第一个元素

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

例如:

type arr1 = ["a", "b", "c"];
type arr2 = [3, 2, 1];

type head1 = First<arr1>; // 应推导出 'a'
type head2 = First<arr2>; // 应推导出 3

解答

type First<T extends any[]> = T[0];

获取元组长度

创建一个 Length 泛型,这个泛型接受一个只读的元组,返回这个元组的长度。

例如:

type tesla = ["tesla", "model 3", "model X", "model Y"];
type spaceX = [
  "FALCON 9",
  "FALCON HEAVY",
  "DRAGON",
  "STARSHIP",
  "HUMAN SPACEFLIGHT"
];

type teslaLength = Length<tesla>; // expected 4
type spaceXLength = Length<spaceX>; // expected 5

解答

type Length<T extends any[]> = T["length"];

实现 Exclude

实现内置的 Exclude<T, U> 类型,但不能直接使用它本身。

从联合类型 T 中排除 U 中的类型,来构造一个新的类型。

例如:

type Result = MyExclude<"a" | "b" | "c", "a">; // 'b' | 'c'

解答

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

Awaited

假如我们有一个 Promise 对象,这个 Promise 对象会返回一个类型。在 TS 中,我们用 Promise 中的 T 来描述这个 Promise 返回的类型。请你实现一个类型,可以获取这个类型。 例如: 例如:Promise<ExampleType>,请你返回 ExampleType 类型。

type X = Promise<string>;
type Y = Promise<{ field: number }>;
type Z = Promise<Promise<string | number>>;
type Z1 = Promise<Promise<Promise<string | boolean>>>;
type Result = MyAwaited<X>; // string
type Result = MyAwaited<Y>; //  { field: number }
type Result = MyAwaited<Z>; // string | number>
type Result = MyAwaited<Z1>; // string | boolean

解答

type MyAwaited1<T> = T extends Promise<infer U>
  ? U extends Promise<any>
    ? MyAwaited1<U>
    : U
  : never;

IF

实现一个 IF 类型,它接收一个条件类型 C ,一个判断为真时的返回类型 T ,以及一个判断为假时的返回类型 F。 C 只能是 true 或者 false, T 和 F 可以是任意类型。 例如:

type A = If<true, "a", "b">; // expected to be 'a'
type B = If<false, "a", "b">; // expected to be 'b'

解答

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

Concat

在类型系统里实现 JavaScript 内置的 Array.concat 方法,这个类型接受两个参数,返回的新数组类型应该按照输入参数从左到右的顺序合并为一个新的数组。 例如:

type Result = Concat<[1], [2]>; // expected to be [1, 2]

解答

type Concat<T extends any[], F extends any[]> = [...T, ...F];

Includes

在类型系统里实现 JavaScript 的 Array.includes 方法,这个类型接受两个参数,返回的类型要么是 true 要么是 false。

例如:

type isPillarMen = Includes<["Kars", "Esidisi", "Wamuu", "Santana"], "Dio">; // expected to be `false`

解答

type Includes<T extends any[], C> = C extends T[number] ? true : false;

Push

在类型系统里实现通用的 Array.push 。

例如:

type Result = Push<[1, 2], "3">; // [1, 2, '3']

解答

type Push<T extends any[], F> = [...T, F];

Unshift

例如:

type Result = Unshift<[1, 2], 0>; // [0, 1, 2,]

解答

type Unshift<T extends any[], F> = [F, ...T];

Parameters

实现内置的 Parameters 类型,而不是直接使用它,可参考 TypeScript 官方文档。

例如:

const foo = (arg1: string, arg2: number): void => {};

type FunctionParamsType = MyParameters<typeof foo>; // [arg1: string, arg2: number]

解答

type MyParameters<T> = T extends (arg1: infer U1, arg2: infer U2) => void
  ? [{ arg: { arg1: U1; arg2: U2 } }]
  : never;