推断TypeScript中的通用函数类型

问题描述 投票:1回答:1

我正在创建一个函数来创建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
typescript types type-inference
1个回答
0
投票

[确定,我已经跟踪到该问题来自重新实现Function的toString。这个想法是,在将函数分配给toString之后,factory不再被视为“ TypeScript函数”,而是以下接口:

© www.soinside.com 2019 - 2024. All rights reserved.