TypeScript中的实用工具类型(Utility Types)
Posted 焱雨
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TypeScript中的实用工具类型(Utility Types)相关的知识,希望对你有一定的参考价值。
TypeScript中的实用工具类型是一些预定义的泛型类型,可用于操作或创建其它新类型。这些实用工具类型在所有TypeScript项目中都是全局可用的,因此无需添加任务依赖项即可使用它们。
1.Partial<Type>
将Type的所有属性都设置为可选的类型。
interface Person name: string; age: number; email: string; type PartialPerson = Partial<Person>; //相当于 // interface Person // name?: string | undefined; // age?: number | undefined; // email?: string | undefined; // interface Todo title: string; description: string; function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) return ...todo, ...fieldsToUpdate ; const todo1 = title: "organize desk", description: "clear clutter", ; const todo2 = updateTodo(todo1, description: "throw out trash", );
2.Required<Type>
与Partical<Type> 相反,该类型由Type中所有属性设置为required组成。
1 interface Person 2 name?: string | undefined; 3 age?: number | undefined; 4 email?: string | undefined; 5 6 7 8 type RequiredPerson = Required<Person>; 9 10 // 相当于 11 // interface Person 12 // name: string; 13 // age: number; 14 // email: string; 15 //
3.Omit<Type, Keys>
构建一个新类型--从类型 Type
中获取所有属性,然后从中剔除 Keys
属性。
interface User id: number; name: string; email: string; age: number; type UserWithoutEmail = Omit<User, \'email\'>; // 相当于 // interface Person // id: string; // name: string; // age: number; //
也可以移除多个属性,
interface User id: number; name: string; email: string; age: number; type UserWithoutEmailAndName = Omit<User, \'email\' | \'name\'>; // 相当于 // interface Person // id: string; // age: number; //
4.Pick<Type, Keys>
从类型 Type
中挑选部分属性 Keys
来构造类型,与Omit相反。
interface User id: number; name: string; email: string; age: number; type UserWithEmailAndName = Pick<User, \'email\' | \'name\'>; // 相当于 // interface Person // name: string; // email: string; //
可以组合使用这些类型,创造新的类型
interface User id: number; name: string; email: string; age: number; type PartialPick = Partial<Pick<User, \'email\' | \'name\'>>; // 相当于 // interface Person // name?: string | undefined; // email?: string | undefined; //
interface User id: number; name: string; email: string; age: number; type OmitPartialPick = Omit<Partial<Pick<User, \'email\' | \'name\'>>, \'email\'>; // 相当于 // interface Person // name?: string | undefined; //
5.Readonly<Type>
通过该Type构造新类型,并将它所有的属性设置为只读的,也就意味着构造出的类型的属性不能被再次赋值。
interface Person id: number; name: string; age: number; type ReadonlyPerson = Readonly<Person>; //相当于 // interface Person // readonly id: number; // readonly name: string; // readonly age: number; // const person: ReadonlyPerson = id: 1, name: \'John\', age: 25 ; person.name = \'Mike\'; // Error: Cannot assign to \'name\' because it is a read-only property.
这个类型可用来表示在运行时会失败的赋值表达式(比如,当尝试给冻结对象的属性再次赋值时)
Object.freeze
function freeze<T>(obj: T): Readonly<T>;
6.Record<Keys, Type>
构造一个对象类型,其属性为Keys,属性值为Type;该实用工具类型可用于将一种类型的属性映射到另一种类型。
interface CatInfo age: number; breed: string; type CatName = "miffy" | "boris" | "mordred"; const cats: Record<CatName, CatInfo> = miffy: age: 10, breed: "Persian" , boris: age: 5, breed: "Maine Coon" , mordred: age: 16, breed: "British Shorthair" , ; cats.boris;
7.Exclude<UnionType, ExcludedMembers>
通过从 UnionType 中排除所有可分配给 ExcludedMembers 的属性来构造一个类型;也就是删除 union 类型的成员来创建新类型。
type T0 = Exclude<"a" | "b" | "c", "a">; type T0 = "b" | "c" type T1 = Exclude<"a" | "b" | "c", "a" | "b">; type T1 = "c" type T2 = Exclude<string | number | (() => void), Function>; type T2 = string | number
8.Extract<Type, Union>
通过从 Type 中提取可分配给 Union 的所有联合成员来构造一个类型,与 Exclude 相反。
type T0 = Extract<"a" | "b" | "c", "a" | "f">; type T0 = "a" type T1 = Extract<string | number | (() => void), Function>; type T1 = () => void
9.NonNullable<Type>
通过从 Type 中排除 null 和 undefined 来构造一个类型。
type T0 = NonNullable<string | number | undefined>; type T0 = string | number type T1 = NonNullable<string[] | null | undefined>; type T1 = string[]
10.ReturnType<Type>
由函数类型 Type
的返回值类型构建一个新类型。
function add(a: number, b: number): number return a + b; type AddReturnType = ReturnType<typeof add>; // type AddReturnType = number; function addStr(a: string, b: string): string return a + b; type AddReturnType2 = ReturnType<typeof addStr>; // type AddReturnType2 = string; type T0 = ReturnType<() => string>; type T0 = string type T1 = ReturnType<(s: string) => void>; type T1 = void type T2 = ReturnType<<T>() => T>; type T2 = unknown type T3 = ReturnType<<T extends U, U extends number[]>() => T>; type T3 = number[]
11.Parameters<Type>
由函数类型 Type
的参数类型来构建出一个元组类型。
function add(a: number, b: string, c:boolean): string return a + b; type AddReturnType = Parameters<typeof add>; // type AddReturnType = [a: number, b: string, c:boolean]; type T0 = Parameters<() => string>; type T0 = [] type T1 = Parameters<(s: string) => void>; type T1 = [s: string] type T2 = Parameters<<T>(arg: T) => T>; type T2 = [arg: unknown]
12.Awaited<Type>
这种类型旨在模拟异步函数中的 await 或 Promises 上的 .then() 方法等操作——具体来说,就是它们递归展开 Promises 的方式。
async function fetchData(): Promise<string> // fetch data from API and return a string type ResolvedResult = Awaited<ReturnType<typeof fetchData>>; // type ResolvedResult = string type A = Awaited<Promise<string>>; type A = string type B = Awaited<Promise<Promise<number>>>; type B = number type C = Awaited<boolean | Promise<number>>; type C = number | boolean
以上,是较常用的一些实用工具类型。
参考资料:
https://www.typescriptlang.org/docs/handbook/utility-types.html#uppercasestringtype
https://dev.to/arafat4693/typescript-utility-types-that-you-must-know-4m6k
从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>
以上是关于TypeScript中的实用工具类型(Utility Types)的主要内容,如果未能解决你的问题,请参考以下文章