Skip to content
☆´∀`☆
On this page

逻辑运算:条件运算 & 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只剩下anyunknown,最后过滤掉any