前言
在typescript
中,当我们省略变量的类型,并在定义时给变量赋默认值时,ts
会帮助我们进行类型自动推断,那么有时候我们没法明确知道一个变量的类型,那么也可以使用infer
手动进行类型推断。
关键词: infer、类型推断、函数、构造方法
1.Parameters<T>
推断函数的参数类型
// 工具类型源码
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
1.1 源码解释:
以上<T extends (...args: any) => any>
是把泛型T
约束为可 可接收任意个参数的函数,并且返回值可以是任意类型。
T extends (...args: infer P) => any ? P : never
表示如果泛型T
的类型满足是一个函数,则使用infer
推断...args
所有参数的类型P
,并返回推断出来的P
类型;泛型不是函数,则返回一个never
不存在的类型。
1.2 使用示例:
function getUser(name: string, age: number) {}
type FnType = typeof getUser // (name: string, age: number) => void
type Params = Parameters<FnType>; // [name: string, age: number]
const user: Params = ['vilan', 18]; // √
const user: Params = ['vilan']; // ×:少了age类型的参数
function getUser2(name: string, age?: number) {}
type FnType = typeof getUser2 // (name: string, age?: number) => void
type Params2 = Parameters<typeof getUser2>; // [name: string, age?: number | undefined]
const user2: Params2 = ['vilan']; // √:参数age是可选的
const user2: Params2 = ['vilan', '18']; // ×:参数age为number类型
1.3 思维发散:
// 1.自定义一个推断函数第一个参数的类型并返回
type FirstParameter<T extends (...args: any) => any> = T extends (value: infer P, ...args: any) => any ? P : never;
function getUser(name: string, age: number) {}
const myName: FirstParameter<typeof getUser> = 'vilan';
// 2.约束泛型只能接收一个参数的函数,并推断其参数类型
type OnlyOneFirstParameter<T extends (value: any) => any> = T extends (value: infer P) => any ? P : never;
function getUser(name: string) {}
const myName: OnlyOneFirstParameter<typeof getUser> = 'vilan';
以上通过ts
内置的typeof
关键字获取函数类型,再通过泛型传入到Parameters<T>
,从而推断出该函数参数的类型。知道了Parameters<T>
的实现原理,自己模仿做一个属于自己的工具类型。
2.ReturnType<T>
推断函数的返回值类型
// 工具类型源码
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
2.1 使用示例
function getUser(name: string, age: number) {
return { name, age }
}
type FnType = typeof getUser // (name: string, age: number) => {name: string; age: number;}
type ReturnValueType = ReturnType<typeof getUser> // {name: string; age: number;}
3.ConstructorParameters<T>
推断构造函数的参数类型
// 工具类型源码
type ConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (...args: infer P) => any ? P : never;
3.1 源码解释:
T extends abstract new (...args: any) => any
其中T
是一个类型参数,限制为构造函数类型。构造函数类型的形式为 abstract new (...args: any) => any
,即一个带有构造签名的类或抽象类。
T extends abstract new (...args: infer P) => any ? P : never;
泛型T
传入的类型满足约束条件,推断出构造函数
的所有参数类型P
,并返回P
类型,否则返回never
表示不存在的类型。
3.2 使用示例
type Params = ConstructorParameters<typeof Persion>; // [name: string, age: number]
type Params2 = ConstructorParameters<new (name: string, age: number) => any> // [name: string, age: number]
const user: Params = ['vilan', 18]; // √
3.3 思维发散:
// 自定义一个推断构造函数第一个参数的类型并返回
type ConsFirstParameter<T extends abstract new (...args: any) => any> = T extends abstract new (value: infer P, ...args: any) => any ? P : never;
class User {
constructor(age: number, name: string) {}
}
const myName: ConsFirstParameter<typeof User> = 18;
4.InstanceType<T>
推断构造函数的返回值类型
// 工具类型源码
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;
4.1 使用示例
class Person {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
type PersionInstance = InstanceType<typeof Person>
const person: PersionInstance = new Person('vilan', 18)
总结
约束函数的泛型可以使用:T extends (...args: any) => any
;
约束构造函数泛型可以使用:T extends abstract new (...args: any) => any
;
获取函数或构造函数类型可以使用:typeof fn
;
类型推断可使用extends
做判断条件,再使用infer
推断指定类型。