中等
获取函数返回类型
不使用 ReturnType 实现 TypeScript 的 ReturnType<T> 泛型。 例如:
const fn = (v: boolean) => {
if (v) return 1;
else return 2;
};
type a = MyReturnType<typeof fn>; // 应推导出 "1 | 2"
解答
type MyReturnType<F> = F extends (...arg: any) => infer U ? U : never;
实现 Omit
不使用 Omit 实现 TypeScript 的 Omit<T, K> 泛型。
Omit 会创建一个省略 K 中字段的 T 对象。
例如:
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = MyOmit<Todo, "description" | "title">;
const todo: TodoPreview = {
completed: false,
};
解答
type MyExclude<T, P> = T extends P ? never : T;
type MyOmit<T, M> = {
[p in MyExclude<keyof T, M>]: T[p];
};
对象部分属性可读
实现一个泛型 MyReadonly2<T, K>,它带有两种类型的参数 T 和 K。
类型 K 指定 T 中要被设置为只读 (readonly) 的属性。如果未提供 K,则应使所有属性都变为只读,就像普通的 Readonly<T>一样。
例如:
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
解答
type myInclude<T, C> = T extends C ? T : never;
type myExclude<T, C> = T extends C ? never : T;
type MyReadonly0<T, F> = {
readonly [k in myInclude<keyof T, F>]: T[k];
};
type MyReadonly1<T, F> = {
[k in myExclude<keyof T, F>]: T[k];
};
type MyReadonly2<T, F> = MyReadonly0<T, F> & MyReadonly1<T, F>;
对象属性只读(递归)
实现一个泛型 DeepReadonly<T>,它将对象的每个参数及其子对象递归地设为只读。
您可以假设在此挑战中我们仅处理对象。不考虑数组、函数、类等。但是,您仍然可以通过覆盖尽可能多的不同案例来挑战自己。
例如:
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 DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends { [K: string]: {} } | any[]
? DeepReadonly<T[P]>
: T[P];
};
元组转合集
实现泛型 TupleToUnion<T>,它返回元组所有值的合集。
例如:
type Arr = ["1", "2", "3"];
type Test = TupleToUnion<Arr>; // expected to be '1' | '2' | '3'
解答
type TupleToUnion<T extends any[]> = T[number];
可串联构造器
在 JavaScript 中我们经常会使用可串联(Chainable/Pipeline)的函数构造一个对象,但在 TypeScript 中,你能合理的给它赋上类型吗?
在这个挑战中,你可以使用任意你喜欢的方式实现这个类型 - Interface, Type 或 Class 都行。你需要提供两个函数 option(key, value) 和 get()。在 option 中你需要使用提供的 key 和 value 扩展当前的对象类型,通过 get 获取最终结果。 例如:
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;
};
}
解答
例如:
解答
例如:
解答
例如:
解答
例如:
解答
例如:
解答
例如:
解答
例如:
解答
例如:
解答
