我正在创建一个函数来创建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;
};
这是创建者函数现在的样子(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
[确定,我已经跟踪到该问题来自重新实现Function的toString
。这个想法是,在将函数分配给toString
之后,factory
不再被视为“ TypeScript函数”,而是以下接口: