infer 一般在 extends 子语句中,infer 会引入一个待推断的类型变量 (如 infer R
) R可以是任意单词字母
这个推断的类型变量可以在有条件类型的 true 分支中被引用
允许出现多个同类型变量的 infer。
type ParamType<T> = T extends (arg: infer R) => any ? R : T;
type s = ParamType<string>;
type n = ParamType<(id: number) => void>;
type o = ParamType<{ id: number }>;
在这个条件语句 T extends (arg: infer R) => any ? R : T; 中,infer R 表示待推断的函数参数。
整句表示为:如果 T 能赋值给 (arg: infer R) => any,则结果是 (arg: infer R) => any 类型中的参数 R,否则返回为 T。
提取函数类型的返回值类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
// type n = number
type n = ReturnType<() => number>;
// type s = string
type s = ReturnType<() => string>;
在协变位置上,同一个类型变量的多个候选类型会被推断为联合类型
type Foo<T> = T extends { a: infer U, b: infer U } ? U : never;
type T10 = Foo<{ a: string, b: string }>; // string
type T11 = Foo<{ a: string, b: number }>; // string | number
在抗变位置上,同一个类型变量的多个候选类型会被推断为交叉类型
type Bar<T> = T extends { a: (x: infer U) => void, b: (x: infer U) => void } ? U : never;
type T20 = Bar<{ a: (x: string) => void, b: (x: string) => void }>; // string
type T21 = Bar<{ a: (x: string) => void, b: (x: number) => void }>; // string & number
返回元组类型的第一个元素如果它类似 string 类型的话
type FirstIfString<T> =
T extends [infer S, ...unknown[]]
? S extends string ? S : never
: never;
// string
type A = FirstIfString<[string, number, number]>;
// "hello"
type B = FirstIfString<["hello", number, number]>;
// "hello" | "world"
type C = FirstIfString<["hello" | "world", boolean]>;
// never
type D = FirstIfString<[boolean, number, string]>;