Appearance
TS 类型挑战
普通难度
1. Pick
ts
type MyPick<T, K extends keyof T> = {
[key in K]: T[key];
};
type MyPick<T, K extends keyof T> = {
[key in K]: T[key];
};
2. Readonly
ts
type MyReadonly<T> = {
readonly [key in keyof T]: T[key];
};
type MyReadonly<T> = {
readonly [key in keyof T]: T[key];
};
3. 元组转换为对象
ts
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'}
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'}
ts
type TupleToObject<T extends readonly any[]> = {
[P in T[number]]: P;
};
type TupleToObject<T extends readonly any[]> = {
[P in T[number]]: P;
};
4. 第一个元素
ts
type arr1 = ["a", "b", "c"];
type arr2 = [3, 2, 1];
type head1 = First<arr1>; // expected to be 'a'
type head2 = First<arr2>; // expected to be 3
type arr1 = ["a", "b", "c"];
type arr2 = [3, 2, 1];
type head1 = First<arr1>; // expected to be 'a'
type head2 = First<arr2>; // expected to be 3
ts
type First<T extends any[]> = T extends [] ? never : T[0];
// or
type First<T extends any[]> = T extends [infer U, ...infer rest] ? U : never;
type First<T extends any[]> = T extends [] ? never : T[0];
// or
type First<T extends any[]> = T extends [infer U, ...infer rest] ? U : never;
5. 获取元组长度
ts
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 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
ts
type Length<T extends readonly any[]> = T["length"];
type Length<T extends readonly any[]> = T["length"];
6. Exclude
ts
type MyExclude<T, U> = T extends U ? never : T;
type MyExclude<T, U> = T extends U ? never : T;
7. Awaited
假如我们有一个 Promise 对象,这个 Promise 对象会返回一个类型。在 TS 中,我们用 Promise<T> 中的 T 来描述这个 Promise 返回的类型。请你实现一个类型,可以获取这个类型。
比如:`Promise<ExampleType>`,请你返回 ExampleType 类型。
ts
type MyAwaited<T> = T extends Promise<infer U>
? U extends Promise<infer E>
? MyAwaited<E>
: U
: never;
type MyAwaited<T> = T extends Promise<infer U>
? U extends Promise<infer E>
? MyAwaited<E>
: U
: never;
7. IF
ts
type A = If<true, "a", "b">; // expected to be 'a'
type B = If<false, "a", "b">; // expected to be 'b'
type A = If<true, "a", "b">; // expected to be 'a'
type B = If<false, "a", "b">; // expected to be 'b'
ts
type If<C, T, F> = C extends true ? T : F;
type If<C, T, F> = C extends true ? T : F;
8. Concat
ts
type Result = Concat<[1], [2]>; // expected to be [1, 2]
type Result = Concat<[1], [2]>; // expected to be [1, 2]
ts
type Concat<T extends any[], U extends any[]> = [...T, ...U];
type Concat<T extends any[], U extends any[]> = [...T, ...U];
9. Includes
ts
type isPillarMen = Includes<["Kars", "Esidisi", "Wamuu", "Santana"], "Dio">; // expected to be `false`
type isPillarMen = Includes<["Kars", "Esidisi", "Wamuu", "Santana"], "Dio">; // expected to be `false`
ts
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y
? 1
: 2
? true
: false;
// 先取出一个类型K,然后用类型K和U比较,如果不相同就递归Includes,继续取P的第一个类型比较
type Includes<T extends readonly any[], U> = T extends [infer K, ...infer P]
? Equal<K, U> extends true
? true
: Includes<P, U>
: false;
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y
? 1
: 2
? true
: false;
// 先取出一个类型K,然后用类型K和U比较,如果不相同就递归Includes,继续取P的第一个类型比较
type Includes<T extends readonly any[], U> = T extends [infer K, ...infer P]
? Equal<K, U> extends true
? true
: Includes<P, U>
: false;
10. push
ts
type Result = Push<[1, 2], "3">; // [1, 2, '3']
type Result = Push<[1, 2], "3">; // [1, 2, '3']
ts
type Push<T extends readonly any[], U> = [...T, U];
type Push<T extends readonly any[], U> = [...T, U];
11. Unshift
typescript
type Result = Unshift<[1, 2], 0>; // [0, 1, 2,]
type Result = Unshift<[1, 2], 0>; // [0, 1, 2,]
ts
type Unshift<T extends readonly any[], U> = [U, ...T];
type Unshift<T extends readonly any[], U> = [U, ...T];
12. Parameters
ts
type MyParameters<T extends (...args: any[]) => any> = T extends (
...args: infer K
) => any
? K
: never;
type MyParameters<T extends (...args: any[]) => any> = T extends (
...args: infer K
) => any
? K
: never;
困难
1. 获取函数返回类型
ts
type MyReturnType<T extends (...args: any[]) => unknown> = T extends (
...args: any[]
) => infer ReturnType
? ReturnType
: never;
type MyReturnType<T extends (...args: any[]) => unknown> = T extends (
...args: any[]
) => infer ReturnType
? ReturnType
: never;
2. 实现 Omit
ts
type MyOmit<T, K extends keyof T> = {
[Key in keyof T as Key extends K ? never : Key]: T[Key];
};
type MyOmit<T, K extends keyof T> = {
[Key in keyof T as Key extends K ? never : Key]: T[Key];
};
3. Readonly(升级版)
ts
interface Todo {
title: string;
description: string;
completed: boolean;
}
const todo: MyReadonly2<Todo, "title" | "description"> = {
title: "Hey",
description: "foobar",
completed: false,
};
todo.title = "Hello"; // Error: cannot reassign a readonly property
todo.description = "barFoo"; // Error: cannot reassign a readonly property
todo.completed = true; // OK
interface Todo {
title: string;
description: string;
completed: boolean;
}
const todo: MyReadonly2<Todo, "title" | "description"> = {
title: "Hey",
description: "foobar",
completed: false,
};
todo.title = "Hello"; // Error: cannot reassign a readonly property
todo.description = "barFoo"; // Error: cannot reassign a readonly property
todo.completed = true; // OK
ts
type MyReadonly2<T, K extends keyof T = keyof T> = {
readonly [Key in keyof T as Key extends K ? Key : never]: T[Key];
} & {
[Key in keyof T as Key extends K ? never : Key]: T[Key];
};
type MyReadonly2<T, K extends keyof T = keyof T> = {
readonly [Key in keyof T as Key extends K ? Key : never]: T[Key];
} & {
[Key in keyof T as Key extends K ? never : Key]: T[Key];
};
4. 深度 Readonly
ts
type X = {
x: {
a: 1;
b: "hi";
};
y: "hey";
};
type Expected = {
readonly x: {
readonly a: 1;
readonly b: "hi";
};
readonly y: "hey";
};
type Todo = DeepReadonly<X>; // should be same as `Expected`
type X = {
x: {
a: 1;
b: "hi";
};
y: "hey";
};
type Expected = {
readonly x: {
readonly a: 1;
readonly b: "hi";
};
readonly y: "hey";
};
type Todo = DeepReadonly<X>; // should be same as `Expected`
ts
type BaseType = string | number | undefined | boolean | null | Function;
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends BaseType ? T[P] : DeepReadonly<T[P]>;
};
type BaseType = string | number | undefined | boolean | null | Function;
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends BaseType ? T[P] : DeepReadonly<T[P]>;
};
5. 元组转合集
ts
type TupleToUnion<T extends readonly any[]> = T[number];
type TupleToUnion<T extends readonly any[]> = T[number];
6. 可串联构造器
ts
declare const config: Chainable;
const result = config
.option("foo", 123)
.option("name", "type-challenges")
.option("bar", { value: "Hello World" })
.get();
// 期望 result 的类型是:
interface Result {
foo: number;
name: string;
bar: {
value: string;
};
}
declare const config: Chainable;
const result = config
.option("foo", 123)
.option("name", "type-challenges")
.option("bar", { value: "Hello World" })
.get();
// 期望 result 的类型是:
interface Result {
foo: number;
name: string;
bar: {
value: string;
};
}
ts
type Chainable<S = {}> = {
option<K extends string, V>(key: K, value: V): Chainable<S & { [P in K]: V }>;
get(): S;
};
type Chainable<S = {}> = {
option<K extends string, V>(key: K, value: V): Chainable<S & { [P in K]: V }>;
get(): S;
};
7. 最后一个元素
ts
type arr1 = ["a", "b", "c"];
type arr2 = [3, 2, 1];
type tail1 = Last<arr1>; // expected to be 'c'
type tail2 = Last<arr2>; // expected to be 1
type arr1 = ["a", "b", "c"];
type arr2 = [3, 2, 1];
type tail1 = Last<arr1>; // expected to be 'c'
type tail2 = Last<arr2>; // expected to be 1
ts
type Last<T extends any[]> = T extends [...unknown[], infer Res] ? Res : never;
type Last<T extends any[]> = T extends [...unknown[], infer Res] ? Res : never;
8. 出堆
ts
type arr1 = ["a", "b", "c", "d"];
type arr2 = [3, 2, 1];
type re1 = Pop<arr1>; // expected to be ['a', 'b', 'c']
type re2 = Pop<arr2>; // expected to be [3, 2]
type arr1 = ["a", "b", "c", "d"];
type arr2 = [3, 2, 1];
type re1 = Pop<arr1>; // expected to be ['a', 'b', 'c']
type re2 = Pop<arr2>; // expected to be [3, 2]
ts
type Pop<T extends any[]> = T extends [...infer R, infer L] ? R : never;
type Pop<T extends any[]> = T extends [...infer R, infer L] ? R : never;
9. Promise.all
ts
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise<string>((resolve, reject) => {
setTimeout(resolve, 100, "foo");
});
// expected to be `Promise<[number, 42, string]>`
const p = Promise.all([promise1, promise2, promise3] as const);
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise<string>((resolve, reject) => {
setTimeout(resolve, 100, "foo");
});
// expected to be `Promise<[number, 42, string]>`
const p = Promise.all([promise1, promise2, promise3] as const);
ts
declare function PromiseAll<T extends readonly any[]>(
values: readonly [...T]
): Promise<{
[Key in keyof T]: T[Key] extends Promise<infer P> ? P : T[Key];
}>;
declare function PromiseAll<T extends readonly any[]>(
values: readonly [...T]
): Promise<{
[Key in keyof T]: T[Key] extends Promise<infer P> ? P : T[Key];
}>;
10. Type Lookup
ts
interface Cat {
type: "cat";
breeds: "Abyssinian" | "Shorthair" | "Curl" | "Bengal";
}
interface Dog {
type: "dog";
breeds: "Hound" | "Brittany" | "Bulldog" | "Boxer";
color: "brown" | "white" | "black";
}
type MyDog = LookUp<Cat | Dog, "dog">; // expected to be `Dog`
interface Cat {
type: "cat";
breeds: "Abyssinian" | "Shorthair" | "Curl" | "Bengal";
}
interface Dog {
type: "dog";
breeds: "Hound" | "Brittany" | "Bulldog" | "Boxer";
color: "brown" | "white" | "black";
}
type MyDog = LookUp<Cat | Dog, "dog">; // expected to be `Dog`
ts
type LookUp<U, T> = U extends { type: infer Type }
? Type extends T
? U
: never
: never;
type LookUp<U, T> = U extends { type: infer Type }
? Type extends T
? U
: never
: never;
11. Trim Left
ts
type Spec = " " | "\n" | "\t";
type TrimLeft<S extends string> = S extends `${Spec}${infer Right}`
? TrimLeft<Right>
: S;
type Spec = " " | "\n" | "\t";
type TrimLeft<S extends string> = S extends `${Spec}${infer Right}`
? TrimLeft<Right>
: S;
12. Trim
ts
type Spec = " " | "\n" | "\t";
type Trim<S extends string> = S extends `${Spec}${infer F}`
? Trim<F>
: S extends `${infer K}${Spec}`
? Trim<K>
: S;
type Spec = " " | "\n" | "\t";
type Trim<S extends string> = S extends `${Spec}${infer F}`
? Trim<F>
: S extends `${infer K}${Spec}`
? Trim<K>
: S;