持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第22天,点击查看活动详情
1. 引言
上一节中,我们结束了TypeScript基础篇章的练习,接下来我们进阶Ts中等篇的题型练习
https://github.com/type-challenges/type-challenges/blob/main/README.zh-CN.md 提供的TypeScript 类型体操姿势合集题型,目的是为了让大家更好的了解TS的类型系统,编写自己的类型工具,或者单纯的享受挑战的乐趣!
2. 题型
- 获取函数返回类型。不使用 ReturnType 实现 TypeScript 的 ReturnType 泛型。 思路: 使用条件类型判断语句,在通过infer 字眼推导函数返回值。 解答:
type MyReturnType<T> = T extends (...arg: any) => infer R ? R : never
type Demo1 = MyReturnType<() => string>
type Demo2 = MyReturnType<() => 123>
type Demo3 = MyReturnType<() => ComplexObject>
type Demo4 = MyReturnType<() => Promise<boolean>>
type Demo5 = MyReturnType<() => () => 'foo'>
type Demo6 = MyReturnType<typeof fn>
type Demo7 = MyReturnType<typeof fn1>
- 实现 Omit,不使用 Omit 实现 TypeScript 的 Omit<T, K> 泛型。Omit 会创建一个省略 K 中字段的 T 对象。 思路: 首先要先通过extends约束确保所抽离的K内容是属于泛型T变量,又因为传入的变量需要获取键值操作,使用到keyof操作符,在通过as 断言重定向 extends 条件类型判断去除对应需要抽离的K键值后的键值(这一步类似filter过滤操作),最后重定向目标对象。结束。 解答:
type MyOmit<T,K extends keyof T>={
[P in keyof T as P extends K ? never : P]: T[P]
}
- 实现一个通用MyReadonly2<T,K>,它带有两种类型的参数T和K。K指定应设置为Readonly的T的属性集。如果未提供K,则应使所有属性都变为只读,就像普通的Readonly一样。
错误思路: 首先要先通过extends约束确保所抽离的K内容是属于泛型T变量,又因为传入的变量需要获取键值操作,使用到keyof操作符,如果使用以下方式先分两步分离操作,第一步获取通过K设置对应的属性为readonly属性
type MyReadonly2<T, K extends keyof T> = {
readonly [P in keyof Pick<T,K>]: T[P]
}
这样,通过第一步就可以把对象T中需要抽取的K对应属性改成readonly,第二步:合并剩下没有被抽取的属性,完整对象内容
type MyReadonly2<T, K extends keyof T> = {
readonly [P in keyof Pick<T,K>]: T[P]
} & {
[P in keyof Omit<T,K>]: T[P]
}
但是,需要注意一点,这样是无法满足如果未提供K,则应使所有属性都变为只读这个要求的,那应该怎么兼容这个需求呢?请看如下:
type MyReadonly2<T, K = keyof T> = {
readonly [P in keyof T as P extends K ? P : never]: T[P]
} & {
[P in keyof T as P extends K ? never : P]: T[P]
}
上述例子还是通过两个步骤第一步,把要readonly 的属性抽离设置,在合并剩下不需要操作的属性,最重要的是K = keyof T 当我们没有传入K值时,默认操作符赋值语句就会把keyof T 联合类型值付给K,这样就满足 如果未提供K,则应使所有属性都变为只读 这一要求