infer ts这一高级语法需要多多练习,勤加编程

ReturnType/Parameters/InstanceType/ConstructorParameters

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/**
* infer涉及的内置高级类型有4个
* ReturnType
* ParameterType
* InstanceType
* ConstructorParameters
*/
interface Member {
name: string;
age: number;
}
export const changeName = <K extends keyof Member>(obj: Member, name: K): Member[K] => {
return obj[name]
}
changeName({name: 'chendap', age: 30}, 'age')

type TestR = ReturnType<typeof changeName> // 返回字面量类型 type TestR = string | number
type TestP = Parameters<typeof changeName> // 返回元祖类型 type TestP = [obj: Member, name: keyof Member]

// 现在看看如何模拟ReturnType/Paramters

type MockReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
type TestMockR = MockReturnType<typeof changeName>
const TestMOckReturn: TestMockR = '111' // is ok
/**
* 1.范型部分的 函数类型表示(...args: any) => any
* 2.正文中的函数类型表示 (...args: any) => any
* 3.infer 后面带出一个新的类型
*/

type MockParameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
type testMockP = MockParameters<typeof changeName> // [obj: Member, name: "name" | "age"]
const TestMock: testMockP =[{age: 22, name: 'cccc'}, 'name'] // is ok
/**
* 1.范型部分跟ReturnType一样
* 2.最难理解的是正文的推断部分
* 3.(...args: infer P) => any ? P : never
*/

class Cpp {
private name
private age
constructor({name, age}: Member) {
this.name = name
this.age = age
}
getName() {
return this.name
}
}
const ClassCppInstance = new Cpp({
name: 'chendap', age: 30
})
export type TTestClassCpp = InstanceType<typeof Cpp>
type MockAge = TTestClassCpp['age'] // type MockAge = number
type MockGetName = TTestClassCpp['getName'] // type MockGetName = () => string

// 现在看看如何实现一个InstanceType

type MockIntanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;
type MockTestCpp = MockIntanceType<typeof Cpp>
type MockAge2 = MockTestCpp['age'] // type MockAge = number
type MockGetName2 = MockTestCpp['getName'] // type MockGetName = () => string


type TConstructor = ConstructorParameters<typeof Cpp> // type TConstructor = [Member]
// 看看如何实现一个ConstructorParameters
type MockConstructorParameters<T extends abstract new (...ars: any) => any> = T extends abstract new (...args: infer P) => any ? P : never;

/**
* infer 主要用于类型提取
*/
interface UserCpp extends Member {
hobby: string
}

type UserPromise = Promise<UserCpp>
// 这个类型表示一个返回值类型为 User的 Promise类型。我们想把 User这个类型从这个已知的函数中提取出来,应当使用 infer关键字
type UnPromisify<T> = T extends Promise<infer V> ? V : never;
type InferUser = UnPromisify<UserPromise>

const testUser: InferUser = {
name: '11',
age: 30,
hobby: 'shufa'
}

/**
- [看懂复杂的 TypeScript 泛型运算](https://mp.weixin.qq.com/s/axfKKGHfxy3gZbKYEFjnkQ)
*/

相关测试题

  • 推断出数组项的类型
    1
    const arrayTest: string[] = ['1', '2' , '3' , '4'] // 推断出array每项里的类型

公布答案

1
2
// infer 提取类型
type XType = typeof arrayTest extends (infer U)[] ? U : never; // string
  • 去掉函数第一个参数
    假设当前我有这样一个type:
    1
    2
    3
    4
    type Obj = {
    getX: (a: string, c: boolean) => void;
    getN: (a: number) => void;
    };
    而我希望将这个type处理成下面这个样子:
    1
    2
    3
    4
    type Obj = {
    getX: (c: boolean) => void;
    getN: () => void;
    };

公布答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type Obj1 = {
getX: (a: string, c: boolean) => void;
getN: (a: number) => void;
};

type Transfer<T> = {
[K in keyof T] :
T[K] extends (s: any, ...args: infer Arg) => any
? (...args: Arg) => ReturnType<T[K]>
: T[K]
}
type TestObj = Transfer<Obj1> // 结果就是对的
type TestObj = {
getX: (c: boolean) => void;
getN: (a: number) => void;
};
  • 增加函数一个参数
    1
    2
    3
    4
    type Obj = {
    getX: (a: string, c: boolean) => void;
    getN: (a: number) => void;
    };
    而我希望将这个type处理成下面这个样子:
    1
    2
    3
    4
    type Obj = {
    getX: (s: string[], a: string, c: boolean) => void;
    getN: (s: string[], a: number) => void;
    };

怎么样做呢

1
2
3
4
5
6
7
8
9
10
type MockParameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never; 

type MockReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

type TransferParmer<T> = {
[K in keyof T]: T[K] extends (...arg: any) => void
? (s: string[], ...arg: MockParameters<T[K]>) => MockReturnType<T[K]>
: T[K]
}
type TestT = TransferParmer<AddParamer>
  • 循环泛型T里面所有的值。
  • 如果T[K]不满足(…arg: any) => any则不处理, 因为T[K]可能不是函数类型。
  • 反之T[K]为函数类型, 则第一个参数为s: string[]。
  • …arg为后续参数类型, Parameters<>为自带方法, 可以推导出函数的所有参数组成的数组的类型。ReturnType<>为自带方法, 可以推导出函数的返回值的类型。

参考文档