打字稿返回类型正在扩大到整个枚举

时间:2019-06-12 15:46:24

标签: typescript

在下面的代码中,如果我没有在每个动作中都使用'as'关键字指定kind,则方法的推断类型会将其扩展为任何Kind类型。有办法避免将“ Kind.PAYPAL重复为Kind.PAYPAL”吗?

enum Kind {
    CASH = 'CASH',
    PAYPAL = 'PAYPAL',
    CREDIT = 'CREDIT'
}

const Cash = () => ({
    kind: Kind.CASH as Kind.CASH,
});

const PayPal = (email: string) => ({
    kind: Kind.PAYPAL as Kind.PAYPAL,
    email
});

const CreditCard = (payload: { cardNumber: string, cvv: string }) => ({
    kind: Kind.CREDIT as Kind.CREDIT,
    payload
});

type PaymentMethod = ReturnType<
    typeof Cash
    | typeof PayPal
    | typeof CreditCard
>;

function describePaymentMethod(method: PaymentMethod): string {
  switch (method.kind) {
    case Kind.CASH:
      // Here, method has type Cash
      return "Cash";

    case Kind.PAYPAL:
      // Here, method has type PayPal
      return `PayPal (${method.email})`;

    case Kind.CREDIT:
      // Here, method has type CreditCard
      return `Credit card (${method.payload.cardNumber})`;
  }
}

1 个答案:

答案 0 :(得分:1)

假设您使用的是TypeScript 3.4或更高版本,则可以按以下方式使用const assertions

const Cash = () => ({
  kind: Kind.CASH as const
});

const PayPal = (email: string) => ({
  kind: Kind.PAYPAL as const,
  email
});

const CreditCard = (payload: { cardNumber: string; cvv: string }) => ({
  kind: Kind.CREDIT as const,
  payload
});

kind属性的类型解释得尽可能狭窄:

Link to code

在TS3.4之前,或者在您不想使用const断言的情况下,您必须依靠TypeScript的heuristics for determining when and when not to widen literals,例如以下帮助函数:

const lit = <T extends string | number | boolean | void | null | {}>(x: T) => x;

,如果可能的话,它返回x作为字符串/数字/布尔文字,因为类型T受包括stringnumber和{{ 1}}。然后您将像这样使用它:

boolean

Link to code

任何一种方法都可以为您工作。希望能有所帮助。祝你好运!