从0开始的 TypeScriptの十四:内置工具类型
序
在之前的《从0开始的TypeScriptの十三》中,已经对typescript
的工具类型中的关键字infer
、extends
、keyof
、typeof
、in
这些有所了解了,那么接下来为了使用更加方便,可以对typescript
中内置的工具类型进行一些学习。
工具类型名称 | 描述 | 用法 |
---|---|---|
Readonly<T> | 将 T 中所有属性都变为只读 | Readonly<{ a: number }> <===> { readonly a: number } |
ReadonlyArray<T> | 返回一个 T 类型的只读数组 | ReadonlyArray<string> <===> readonly string[] |
Partial<T> | 将 T 中所有的属性都变成可选类型 | Partial<{ a: number }> <===> { a?: number } |
Required<T> | 将 T 中所有的属性都变成必选类型 | 和上面的Partial 正好相反 |
Pick<T, K extends keyof T> | 从 T 中摘取部分属性 | Pick<{ a: number, b: string, c: boolean }, 'a' \| 'c'> <===> { a: number, c: boolean } |
Omit<T, K extends keyof T> | 从 T 中排除部分属性 | Omit<{ a: number, b: string, c: boolean }, 'a' \| 'c'> <===> { b: string } |
Exclude<T, U> | 从 T 中剔除可以赋值给 U 的类型 | Exclude<number \| string \| boolean, string> <===> number \| boolean |
Extract<T, U> | 提取 T 中可以赋值给 U 的类型 | Exclude<number \| string \| boolean, string> <===> string |
Record<K, T> | 返回属性名为 K,属性值为 T 的类型 | Record<'a' \| 'b', () => void> <===> { a: ()=>void, b: ()=>void } |
NonNullable<T> | 从 T 中剔除 null 和 undefined | NonNullable<string \| null \| undefined> <===> string |
ConstructorParameters<T> | 获取 T 的构造函数参数类型组成的元组 | Compare是类,构造函数constructor(a: number, b:number){ ... } 。 ConstructorParameters<typeof Compare> <===> [ a: number, b: number] |
InstanceType<T> | 由构造函数类型T的实例类型来构建一个新类型 | InstanceType<typeof Compare> <===> Compare |
Parameters<T> | 获取函数参数类型组成的元组 | Parameters<(a: number, b: string) => number> <===> [ a: number, b: number] |
ReturnType<T> | 获取函数返回值类型 | ReturnType<(a: number, b: string) => number> <===> number |
上面这些内置的工具类型能够很大程度上简化代码。
比如说给定一个interface
接口,需要将内部所有属性都变成可选类型
虽然我们自己也可以写,但是如果直接使用现有的内置工具类型Partial
不是更好么
interface A {
name: string,
age: number,
action: ()=>void
}
type PartialFun<T> = {
[K in keyof T] ? : T[K]
}
type _A = PartialFun<A>
或者说我在网上看到的一道转换题目:
- 如何定义一个
SetOptional
工具类型,支持把给定的keys
对应的属性变成可选的?
type Foo = {
a: number;
b?: string;
c: boolean;
}
// 测试用例
type SomeOptional = SetOptional<Foo, 'a' | 'b'>;
这样在修改时思考方式,需要对Foo
与a | b
匹配的属性拆除来变成可选,然后不匹配的属性维持不变,最后将可选和不可选通过&
进行联合
// 对应的属性变成可选
type CommonFun<T, K> = {
[ t in keyof T as t extends K ? t: never] ?: T[t]
}
// 不对应的属性
type Unequal<T, K> = {
[ t in keyof T as t extends K ? never: t] : T[t]
}
type SetOptional<T, K> = CommonFun<T, K> & Unequal<T, K>
不过这样虽然思路很清晰,但是看起来写了好多。事实上,可以使用Partial
和Pick
来代替CommonFun
, 然后用Omit
代替Unequal
只需要像下面的一句就可以解决,是不是缩减了很多代码
type SetOptional<T, K extends keyof T> = Partial<Pick<T, K>> & Omit<T, K>
当然这些都是要基于对typescript
内置类型比较熟悉的情况下,最好的方式就是多多去使用。就像当初最开始学习javascript
时,对于Math.floor
、splice
这些方法也是多使用才能够熟悉起来。
当然上面的这些例子可能会觉得实用性不大,那么将数组类型扁平化总应该算有点实用性吧
将[ number, [string], [ boolean, [ void, string ] ] ]
转换成 number | string | boolean | void
扁平化联合
这种例子很容易就会想到递归函数
解决方案:首先使用infer X[]
将当前数组中的元素进行判断,如果不是数组则直接返回,否则元素重新进入SetOptional
判断循环。
type ArrType = [ number, [string], [ boolean, [ void, string ] ] ]
type SetOptional<T> = T extends (infer X)[] ? SetOptional<X> : T
// string | number | boolean | void
type Res = SetOptional<ArrType>
- 点赞
- 收藏
- 关注作者
评论(0)