内置的必填泛型不够灵活,RequiredByKeys 泛型来救场。
为了帮助读者更好地巩固 TypeScript 的知识,我从 Github 上的 type-challenges 库中选择了几十个挑战,与您一起完成类型挑战。
挑战
实现一个通用的 RequiredByKeys<T, K>
方法,它接受两个类型参数 T
和 K
。
K
指定了 T
的属性集,这些属性应该设置为必需的。当没有提供 K
时,它应该像正常的 Required<T>
一样设置所有必需的属性。
例如:
interface User {
name?: string
age?: number
address?: string
}
type UserRequiredName = RequiredByKeys<User, 'name'>
// { name: string; age?: number; address?: string }
解决方案
我们的类型挑战是实现 RequiredByKeys<T, K>
泛型,当 K
没有提供时,它应该像普通的 Required<T>
一样提供所有所需的属性。
Required< T >
构造一个类型,其中包含 Type
的所有属性设置为 required。
Required<T>
是 TypeScript 的内置工具类型,在 typescript/lib/lib.es5.d.ts
文件中定义:
/**
* Make all properties in T required.
* typescript/lib/lib.es5.d.ts
*/
type Required<T> = {
[P in keyof T]-?: T[P];
};
Required<T>
泛型在内部使用了 TypeScript 的映射类型,其语法如下
其中 P in K
类似于 JavaScript 中的 for...in
语句,用于遍历类型 K
中的所有类型,以及类型变量 T
,用于表示 TypeScript 中的任何类型。
你也可以在映射过程中使用额外的修饰符只读和问号(?) 。通过添加加号( )和减号(-)前缀来添加和删除相应的修饰符。如果不添加前缀,默认使用加号。
在介绍了映射类型的相关知识之后,实现 RequiredByKeys
泛型的思路就非常简单了。
从上图可以看出,我们只需要选择与 K 相关的属性,按照需要设置并生成一个新的对象类型,然后根据剩下的属性构建另一个对象类型,最后使用 &
操作符将上述两个对象类型组合成一个新的对象类型。
像专家一样使用 TypeScript 的交集类型你应该知道的关于 TypeScript 交集类型的细节。当你学习 TypeScript 时,你可以把类型理解为值的集合,https://mp.weixin.qq.com/s?__biz=MzU3NjM0NjY0OQ==&mid=2247485067&idx=1&sn=7de40cecc1daec297a5c5f18b838e6bb&chksm=fd1409fdca6380ebc23e31077815561d182197481150167639b5b1f32a7e67d0a5379a794cc7&token=1779636375&lang=zh_CN#rd
完整代码
最后,让我们看一下完整的代码:
TypeScript 4.1 允许我们使用 as 子句在映射类型中重新映射键,其语法如下:
type MappedTypeWithNewKeys<T> = {
[K in keyof T as NewKeyType]: T[K]
// ^^^^^^^^^^^^^
// New Syntax!
}
其中NewKeyType的类型必须是 string | number | symbol
联合类型的子类型,在重新映射键的过程中,我们可以通过返回never类型来过滤键。
Merge
泛型的作用是合并对象类型,除了上述的解决方案,还有一种更简洁的方式。
type RequiredByKeys<T, K = keyof T> = Merge<
T & {
[P in keyof T as P extends K ? P : never]-?: T[P]
}
>
这个挑战涉及到的主要知识是 TypeScript 的映射类型,如果你想了解更多关于映射类型的信息,可以阅读以下文章:
像专家一样使用TypeScript映射类型http://mp.weixin.qq.com/s?__biz=MzU3NjM0NjY0OQ==&mid=2247484965&idx=1&sn=3e95787a17188b63769934fc42c5d72f&chksm=fd140953ca638045cf19f7915e04221ff2bc7d24aaa83f752b430e01d08c37baacf277e24876&scene=21#wechat_redirect
如果你有其他的解决方案,你可以给我发消息。
欢迎关注公众号:文本魔术,了解更多