我正在尝试定义一个将采用一组函数并将其包装在MobX的flow
中的函数。我的实际代码并不仅仅是用flow
包装,但这对这个问题并不重要。我设计了一些可以成功完成映射的TypeScript类型,但是在获取与类型匹配的函数时遇到了麻烦。
首先,我认为我可以像这样使用lodash的mapValues
:
const actions = {
a: function* (a: number) { return "test" },
b: function* (b: string) { return 1 }
};
const flowed = mapValues(actions, f => flow(f));
但是mapValues
的输入假定每个属性都具有相同的类型,因此会产生错误:
(parameter) f: ((a: number) => Generator<never, string, unknown>) | ((b: string) => Generator<never, number, unknown>)
Argument of type '((a: number) => Generator<never, string, unknown>) | ((b: string) => Generator<never, number, unknown>)' is not assignable to parameter of type '(a: number) => Generator<any, string, any> | AsyncGenerator<any, string, any>'.
Type '(b: string) => Generator<never, number, unknown>' is not assignable to type '(a: number) => Generator<any, string, any> | AsyncGenerator<any, string, any>'.
Types of parameters 'b' and 'a' are incompatible.
Type 'number' is not assignable to type 'string'.ts(2345)
做了一些研究和实验,我想到了以下通用类型来进行转换:
type Flowing<T> = T extends (...args: infer A) => Generator<any, infer R, any> ? (...args: A) => Promise<R> : never;
type Flowify<T> = {
[P in keyof T]: Flowing<T[P]>;
}
declare function flowify<T>(o: T): Flowify<T>;
const flowed = flowify(actions);
现在flowed
具有正确的类型:
{
a: (a: number) => Promise<string>;
b: (b: string) => Promise<number>;
}
问题是我还没有弄清楚如何创建flowify
函数,以便它与类型匹配而不进行转换。这是我到目前为止的内容,但我想避免使用as
:
function flowify<T extends object>(o: T): Flowify<T> {
return mapValues(o, f => flow(f as any)) as Flowify<T>;
}
我已经在这个任务上工作了几个小时,希望能引起专家的注意。我已经在TypeScript Playground中获得了这段代码。