infer
是ts中用于推断类型的关键字组合,一般与条件类型和泛型一起使用。通过使用infer,可以在函数签名中提取函数返回值类型,并将其用作泛型参数
我们常常使用infer来编写一些类型工具,通过infer来推断类型并使用它们进行类型操作和约束。这在一些高级类型推断的场景中非常有用,以下是一些例子
获取函数的返回类型
type Return<T> = T extends (...args: any[]) => infer R ? R : T;
type sum = (a: number, b: number) => number;
type concat = (a: any[], b: any[]) => any[];
type a = symbol;
const b: number = 123;
type sumReturn = Return<sum>; // number
type concatReturn = Return<concat>; // any[]
type aReturn = Return<a>; // symbol
type bReturn = Return<typeof b>; // number
function greet(): string {
return "Hello, TypeScript!";
}
type greetReturn = Return<typeof greet>; // string
const userName: greetReturn = "ray";
// -------------------------------
let sumReturnType: ReturnType<sum>; // number
type concatReturnType = ReturnType<concat>; // any[]
type greetReturnType = ReturnType<typeof greet>; // string
type aReturnType = ReturnType<a>;
// 类型“symbol”不满足约束“(...args: any) => any”。ts(2344)
type bReturnType = ReturnType<typeof b>;
// 类型“number”不满足约束“(...args: any) => any”。ts(2344)
const job: greetReturnType = "frontend";
// string
在上面的例子中,我们定义了一个Return<T>
类型,它接受一个函数类型T作为输入并返回该函数的返回值类型。使用ts infer
,我们从函数签名中推断了返回值类型R
,并将其用作Return
的结果类型。
(...args: any[]) => infer R
代表是否为一个函数,如果是使用infer
推断出函数的返回值类型R
,否则返回T
细心的你会发现,这个Return<T>
与ts内置工具ReturnType
类似,不同的是ReturnType
如果传入的不是一个函数,会抛出异常
获取函数第一参数的类型
type FirstArgType<T> = T extends (x: infer F, ...args: any[]) => any ? F : T;
type greetType = (a: number, b: string, c: Function) => void;
let greetFirstArgType: FirstArgType<greetType>;
// number
const exampleFunction = (a: string, b: Function) => {};
type ExampleFunctionFirstArgType = FirstArgType<typeof exampleFunction>;
// string
在上面的例子中,我们定义了一个FirstArgType<T>
类型,它接受一个函数类型T
作为输入并返回该函数的第一个参数类型。使用ts infer
,我们从函数签名中推断了函数的第一个参数类型R
,并将其用作FirstArgType
的结果类型。
获取数组每一项的类型
type ArrayItemType<T> = T extends Array<infer U> ? U : never;
type ItemType1 = ArrayItemType<[string, number]>;
// type ItemType1 = string | number
type ItemType2 = ArrayItemType<string[]>;
// type ItemType2 = string
const array1 = [1, 2, 3];
type ItemType3 = ArrayItemType<typeof array1>;
// type ItemType3 = number
const array2 = [
1,
"ray",
{ a: 123, b: "frontend" },
() => 123,
() => "frontend",
];
type ItemType4 = ArrayItemType<typeof array2>;
/**
*
type ItemType4 = string | number | (() => number) | (() => string) | {
a: number;
b: string;
}
*/
在上面的例子中,我们定义了一个ArrayItemType<T>
类型,它接受一个函数类型T作为输入并返回数组每一项的参数类型。使用ts infer
,我们从数组中每一项参数类型R
,并将其用作ArrayItemType
的结果类型。