“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第2篇文章,点击查看活动详情”
- 想着锻炼一下自己 TS 的能力,就去找 antfu 老师的 TS 题目了,然后做的有些崩溃,想清楚之后来总结一下。
第一题
Question
实现 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,
}
> View on GitHub: https://tsch.js.org/4
/* _____________ Your Code Here _____________ */
type MyPick<T, K> = any
/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<Expected1, MyPick<Todo, 'title'>>>,
Expect<Equal<Expected2, MyPick<Todo, 'title' | 'completed'>>>,
// @ts-expect-error
MyPick<Todo, 'title' | 'completed' | 'invalid'>,
]
interface Todo {
title: string
description: string
completed: boolean
}
interface Expected1 {
title: string
}
interface Expected2 {
title: string
completed: boolean
}
此处答案为
type MyPick<T, K extends keyof T> = {
[key in K]: T[key]
}
就是说 K 只能扩展于 T 的 key ,然后对在 K 中的键值对应起来。
第二题
不要使用内置的Readonly<T>,自己实现一个。
该 Readonly 会接收一个 泛型参数,并返回一个完全一样的类型,只是所有属性都会被 readonly 所修饰。
也就是不可以再对该对象的属性赋值。
/* _____________ 你的代码 _____________ */
type MyReadonly<T> = any
/* _____________ 测试用例 _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<MyReadonly<Todo1>, Readonly<Todo1>>>,
]
interface Todo1 {
title: string
description: string
completed: boolean
meta: {
author: string
}
}
- 解答
type MyReadonly<T> = {
readonly [key in keyof T]: T[key]
}
- 其实之前做完这两道题的时候就满疑惑的,这都是啥,为啥一下
extends keyof,一下in,又一下in keyof
这里啊,我们还是要分而析之!
extends
A extends B 的含义是,A 是 B 的子集
keyof
A key of B 的含义是,A 是 B 的key的集合
in
A in B 的含义是,对B中的每一个值进行遍历
- 了解了这些东西之后,再来看这两个题目就比较好理解了。