Typescript-Infer 的使用
文章目录

Infer 用于表示在 extends 条件语句中待推断的类型变量

简单的使用方法参考 Typescript-Cheatsheet

这里有一个复杂的示例:

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
91
92
93
interface Action<T> {
payload?: T;
type: string;
}

class EffectModule {
count = 1;
message = "hello!";

delay(input: Promise<number>) {
return input.then((i) => ({
payload: `hello ${i}!`,
type: "delay",
}));
}

setMessage(action: Action<Date>) {
return {
payload: action.payload!.getMilliseconds(),
type: "set-message",
};
}
}

/* ------------Requirement--------------- */

/*
修改下方Connect 以满足后续的类型检查



type Connect = (module: EffectModule) => any;



主要目的:

1. 省略非函数的属性
2. 对函数的类型检查进行 转换

转换细节:


asyncMethod<T, U>(input: Promise<T>): Promise<Action<U>>
变成了 ↓
asyncMethod<T, U>(input: T): Action<U>


syncMethod<T, U>(action: Action<T>): Action<U>
变成了 ↓
syncMethod<T, U>(action: T): Action<U>


*/

/* ------------Solution Start-------------- */
/* 1. FuncName 类型, 过滤掉不是 Function 的属性 */
type FuncName<T> = {
[P in keyof T]: T[P] extends Function ? P : never;
}[keyof T];

/* 2. Connect 类型, 对函数类型进行转换, 核心就是使用了 infer 关键字, 注意在这个地方使用了很多个 trinary operator 进行条件检查 */
type Connect = (module: EffectModule) => {
[T in FuncName<EffectModule>]: EffectModule[T] extends (
arg: Promise<infer T>
) => Promise<infer U>
? (arg: T) => U
: EffectModule[T] extends (arg: Action<infer T>) => Action<infer U>
? (arg: T) => Action<U>
: never;
};
/* ------------Solution End -------------- */

const connect: Connect = (m) => ({
delay: (input: number) => ({
type: "delay",
payload: `hello 2`,
}),
setMessage: (input: Date) => ({
type: "set-message",
payload: input.getMilliseconds(),
}),
});



type Connected = {
delay(input: number): Action<string>;
setMessage(action: Date): Action<number>;
};

export const connected: Connected = connect(new EffectModule());