几个案例,带你学习typescript类型推断

197 阅读3分钟

前言

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推断指定类型。