【发布时间】:2020-09-09 08:39:12
【问题描述】:
我正在创建一个函数来创建 Redux 操作(例如来自 redux 工具包的 createAction)。我需要一个返回动作生成器的函数,我希望这个生成器是通用的,基于提供给创建者函数的类型。
const createGenericAction = <T extends string>(type: T) => <
A extends {},
B extends {}
>(
payloadGenerator: (a: A) => B
) => {
const factory = (payload: A) => ({
type,
payload: payloadGenerator(payload),
});
factory.toString = (() => type) as () => T;
return factory;
};
这就是 creator 函数现在的样子(toString 的实现是由于与 redux-toolkit 的兼容性)。
payloadGenerator 不是泛型时可以正常工作,所以:
const someAction = createGenericAction('someAction')(
(payload: { a: number; b: string }) => payload
);
类型正确。
虽然,当payloadGenerator 是泛型时,整个类型推断就会分崩离析:
const someAction = createGenericAction('someAction')(
<T extends string>(payload: { value: T }) => payload
);
Argument of type '<T extends string>(payload: { value: T; }) => { value: T; }' is not assignable to parameter of type '(a: {}) => { value: string; }'.
Types of parameters 'payload' and 'a' are incompatible.
Property 'value' is missing in type '{}' but required in type '{ value: string; }'.ts(2345)
更复杂的例子
enum Element {
Elem1 = 'elem1',
Elem2 = 'elem2',
}
type ElementValueMapper = {
[Element.Elem1]: string;
[Element.Elem2]: number;
};
const someAction = createGenericAction('someAction')(
<T extends Element>(payload: { e: T; value: ElementValueMapper[T] }) =>
payload
);
这样的操作应该允许调用:
someAction({ e: Element.Elem1, value: 'string' }); // okay
someAction({ e: Element.Elem2, value: 5 }); // okay
但不允许:
someAction({ e: Element.Elem1, value: 5 }); // error value should be type string
【问题讨论】:
标签: typescript types type-inference