逻辑运算:条件运算 & infer 推断
条件运算
条件运算和三元表达式差不多,常与函数中的泛型相搭配。
比如,为给联合类型的泛型函数推断返回类型:
ts
// function addSomething<T extends number | string | bigint> (x: T, y: T) {
// return x + (y as any)
// }
type LimitType<T extends number | string | bigint> = T extends number ? number : T extends string ? string : T extends bigint ? bigint : never;
function addSomething<T extends number | string | bigint> (x: T, y: T): LimitType<T> {
return x + (y as any)
}
addSomething(1, 1)
addSomething('xxx', 'xxx')
infer 关键字
infer
关键字可以用来在条件类型中提取类型的某一部分信息。
TIP
infer
只能被用在条件类型中。
infer R
代表推断 R 的类型。
在函数中使用infer
可以用inter
来推断函数的返回类型:
ts
type Func = (...arg: any[]) => any;
type FunctionReturnType<T extends Func> = T extends (...arg: any[]) => infer R ? R : never;
function add (a: number) {
return a++
}
type AddFunc = typeof add;
type AddReturnType = FunctionReturnType<AddFunc>;
- 推断第一个入参的类型:
ts
type FunctionType = (...args: any) => any;
type FirstParameter<T extends FunctionType> = T extends (arg: infer R, ...args: any) => any ? R : never;
type A = FirstParameter<(a: number) => void>; // number
在数组中使用infer
ts
type Swap<T extends any[]> = T extends [infer A, infer B] ? [B, A] : T;
type SwapRes1 = Swap<[1, 2]>; // [2,1]
type SwapRes2 = Swap<[1, 2, 3]>; // [1,2,3] 不符合条件 没置换
提取数组收尾类型:
ts
type ExtractStartAndEnd<T extends any[]> = T extends [infer A, ...any[], infer B] ? [A, B] : T;
type Res1 = ExtractStartAndEnd<[1, 2, 3, 4]>; // 1,5
调换数组首尾类型:
ts
type SwapStartAndEnd<T extends any[]> = T extends [infer A, ...infer B, infer C] ? [C, ...B, A] : T;
在接口中使用infer
提取对象中的某些属性的属性值类型
ts
type PropType<T, K extends keyof T> = T extends {
[Key in K]: infer R;
}
? R
: never;
type Res1 = PropType<{ name: string }, 'name'>; // string
type Res2 = PropType<{ name: string; age: number }, 'name' | 'age'>; // string | number
反转键值对
ts
type ReverseKeyValue<T extends Record<string, unknown>> = T extends Record<infer K, infer V> ? Record<V & string, K> : never;
type Res1 = ReverseKeyValue<{ xxx: 'a' }>; // { a: "xxx";}
type Res2 = ReverseKeyValue<{ xxx: () => void }>; // {[x: (() => void) & string]: "xxx"}
带约束的 infer
infer P extends
,比如只提取第一个类型为字符串的成员:
ts
type FirstArrayItemType<T extends any[]> = T extends [infer P extends string, ...any[]] ? P : never;
type A = FirstArrayItemType<['xxx', 'abc']>; // xxx
type B = FirstArrayItemType<[12, 'abc']>; // never
TypeScript 4.7
分布式条件类型
分布式条件类型也称为是条件类型的分布式特征。
ts
type Condition<T> = T extends 1 | 2 | 3 ? T : never;
type Res1 = Condition<1 | 2 | 3 | 4>; // 1|2|3
type Res2 = 1 | 2 | 3 | 4 extends 1 | 2 | 3 ? 1 | 2 | 3 | 4 : never; // never
其中Res1
就使用到了分布式条件类型:
- 类型参数为联合类型
- 类型参数通过泛型传入
什么是分布式特性
将入参的联合类型拆开来,对每个类型进行一次条件判断,最后再将结果合并为一个联合类型返回。
不想使用分布式条件类型
可以用数组包裹泛型:
ts
type Condition<T> = [T] extends [1 | 2 | 3] ? T : never;
type Res1 = Condition<1 | 2 | 3 | 4>; // never
utils
isNever
ts
type IsNever<T> = [T] extends [never] ? true : false;
isAny
ts
type IsAny<T> = 0 extends 1 & T ? true : false;
0 extends 1
始终为 false,利用any
的特性,当传入类型为 any 时,则为 true。
isUnknown
ts
type IsUnknown<T> = unknown extends T ? (IsAny<T> extends true ? false : true) : false;
unknown extends T
只剩下any
和unknown
,最后过滤掉any
。