实现 Pick
题目: 传送门
从类型 T 中选择出包含在集合 K 中的属性,构造成一个新的类型。(即实现 TS 内置的 Pick<T, K>)
例如:
interface Todo {
title: string
description: string
completed: boolean
}
type TodoPreview = MyPick<Todo, 'title' | 'completed'>
思路与要点:
TS 中,可以使用 extends 运算符来判断一个属性是否在集合类型 Union Type 中:
例如:
type r1 = 'title' extends 'title' | 'completed' ? true : false // type r1 = true
利用这个特性,我们可以实现这样一种类型:
type MyPick<T, P> = {
[K in keyof T]: K extends P ? never : T[K]
}
但这样我们会发现,不属于类型 P 的属性会变成 never:
type r2 = MyPick<Todo, 'title' | 'completed'>
/**
* type r2 = {
* title: string
* description: never
* completed: boolean
* }
*/
由此,我们需要排除掉 K 中不属于 P 的类型,可以实现一个工具类型 Exclude:
type Exclude<T, U> = T extends U ? never : T
然后改造 MyPick 的实现形式:
type MyPick<T, P extends keyof T /* 约束 P 的类型,只允许从 T 的属性中取值 */> = {
[K in Exclude<keyof T, P>]: T[K]
}
来看下最后的结果:
type r3 = MyPick<Todo, 'title' | 'completed'>
/**
* type r3 = {
* title: string
* completed: boolean
* }
*/
符合要求🥳。
实现 Readonly
题目:传送门
将类型 T 中所有的属性,标记为 readonly。(即实现 TS 内置的 Readonly<T>)
例如:
interface Todo {
title: string
description: string
}
type TodoReadonly = MyReadonly<Todo>
/**
* type TodoReadonly = {
* title: readonly string
* description: readonly string
* }
*/
思路与要点:
这道题考察点比较简单,我们只需要遍历类型 T 中的所有属性,然后给它们加上 readonly 修饰就可以了:
type MyReadonly<T> = {
[K in keyof T]: readonly T[K]
}
来看下结果:
type r4 = MyReadonly<Todo>
/**
* type r4 = {
* title: readonly string
* description: readonly string
* }
*/
也是符合要求的🥳。