在 TypeScript 中推断泛型函数类型
Posted
技术标签:
【中文标题】在 TypeScript 中推断泛型函数类型【英文标题】:Inferring generic function type in TypeScript 【发布时间】: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
【问题讨论】:
【参考方案1】:好的,我发现这个问题来自重新实现 Function 的 toString
。这个想法是在将函数分配给toString
之后,factory
不再被视为“TypeScript函数”,而是如下接口:
(payload: A):
payload: B;
;
toString(): A;
并且这个界面的一部分是正确的,但是factory
的整个类型不是我想要的。实际上,JS 中的每个函数(TS 中也是如此)都是function
类型,并且来自Function
原型,其中确实包含toString
,但是TypeScript 确实区分了这些类型并且Function
并不经常使用。
没有太多的题外话,解决办法是断言类型为factory
:
const createGenericAction = <A extends string>(code: A) => <
A extends ,
B extends
>(
payloadGenerator: (a: A) => B
) =>
const factory: (payload: A) => payload: B = (payload: A) => (
payload: payloadGenerator(payload),
);
factory.toString = () => code;
return factory;
;
【讨论】:
我很好奇 redux-toolkit 如何解决这个问题,即使 @TomaszBłachut 它没有,github.com/reduxjs/redux-toolkit/issues/584以上是关于在 TypeScript 中推断泛型函数类型的主要内容,如果未能解决你的问题,请参考以下文章