type Foo = {
(trx: Transaction | undefined, event: SomeEnum.OPT_1, params: { whatever: number }): Promise<void>;
(trx: Transaction | undefined, event: SomeEnum.OPT_2, params: { whatever: string }): Promise<void>;
};
export const foo: Foo = async (trx: Transaction | undefined, event: SomeEnum, params: object | undefined) => {};
我正在尝试函数重载,上面的代码可以工作,但在我的现实情况下,我将有大约 40 个重载,其中只有一些参数会有所不同,所以我想知道,有没有办法改进代码,这样我就不必一遍又一遍地复制所有不变的元素?在示例中,第一个参数 trx 始终相同,函数的返回类型也始终相同。我尝试过这样的东西,但 typescript 显然不喜欢它:
type FooPartial<T1 extends SomeEnum, T2> = (trx: Transaction | undefined, event: T1, params: T2) => Promise<void>;
type Foo {
FooPartial<SomeEnum.OPT_1, { whatever: number }>
FooPartial<SomeEnum.OPT_2, { whatever: string }>
}
最佳答案
您需要进行动态重载。
为了做到这一点,您需要:
- 计算循环中的每个重载
type Transaction = {
tag: 'Transaction'
}
type Maps = {
[SomeEnum.OPT_1]: string;
[SomeEnum.OPT_2]: number
}
type Overloading = {
[Ev in keyof Maps]: (trx: Transaction | undefined, event: Ev, params: Maps[Ev]) => Promise<void>
}
- 现在我们应该只获取
Overloading
类型的值
type Values<T> = T[keyof T]
type Overloading = Values<{
[Ev in keyof Maps]: (trx: Transaction | undefined, event: Ev, params: Maps[Ev]) => Promise<void>
}>
- 现在,当我们拥有所有允许的函数的并集时,我们需要将此并集转换为重载函数。为此,您只需使用交集
&
。
// credits goes to https://stackoverflow.com/a/50375286
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I
) => void
? I
: never;
type Overloading =UnionToIntersection<Values<{
[Ev in keyof Maps]: (trx: Transaction | undefined, event: Ev, params: Maps[Ev]) => Promise<void>
}>>
完整代码
enum SomeEnum {
OPT_1 = '1',
OPT_2 = '2'
}
type Transaction = {
tag: 'Transaction'
}
type Maps = {
[SomeEnum.OPT_1]: string;
[SomeEnum.OPT_2]: number
}
type Values<T> = T[keyof T]
// credits goes to https://stackoverflow.com/a/50375286
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I
) => void
? I
: never;
type Overloading =UnionToIntersection<Values<{
[Ev in keyof Maps]: (trx: Transaction | undefined, event: Ev, params: Maps[Ev]) => Promise<void>
}>>
export const foo: Overloading = async (trx: Transaction | undefined, event: SomeEnum, params: Values<Maps>) => { };
foo({tag:'Transaction'}, SomeEnum.OPT_1, 'string') // ok
Here ,在我的博客中,你可以找到类似的解决方案
关于typescript - 更干净的功能重载,无需复制不改变的部分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68365226/