【问题标题】:Stricter union types when using mapped types in TypeScript在 TypeScript 中使用映射类型时更严格的联合类型
【发布时间】:2019-01-27 22:04:16
【问题描述】:

在映射中使用联合类型时,我正在尝试使用映射类型来提供更多类型安全性。当使用属性类型(例如['value'])作为键的类型(K)时,似乎没有办法在键/值之间提供类型安全。

我想避免手动创建一个独特的模型来实现这一点。

代码:

interface IAction { value: string; }

type ActionMapper<A extends IAction> = {
   [K in A['value']]: A;
}

interface IActionOne { value: 'action_one' }

interface IActionTwo { value: 'action_two' }

type Actions = IActionOne | IActionTwo;

const reducerMap: ActionMapper<Actions> = {
  action_one: { value: 'action_one' },
  action_two: { value: 'action_one' }, // expecting this line to fail
}

我已经注释了我预计会失败的行。

我觉得我应该能够利用密钥 (K in) 来提供正确的类型作为值。但是,我目前使用A,它提供了IAction 实现,其中value 的类型为string - 我想避免这种情况。

这在当前版本的 TypeScript 中是否可行?

【问题讨论】:

    标签: typescript types discriminated-union union-types mapped-types


    【解决方案1】:

    是的,可以为所欲为。

    正如您所注意到的,您的问题是ActionMapper&lt;A&gt; 的属性值始终为A。对于Actions,这是一个联合类型。您真正想要做的是从A 中提取与{value: K} 匹配的每个键K 的成分。幸运的是,有一个名为 Extractpre-defined conditional type 可以为您执行此操作。让我们重新定义ActionMapper&lt;A&gt;

    type ActionMapper<A extends IAction> = {
       [K in A['value']]: Extract<A, {value: K}>;
    }
    

    现在我们再试一次:

    const reducerMap: ActionMapper<Actions> = {
      action_one: { value: 'action_one' },
      action_two: { value: 'action_one' }, // error!
      // Type '"action_one"' is not assignable to type '"action_two"'.
    }
    

    你得到了你预期的错误。希望有帮助。祝你好运!

    【讨论】:

      猜你喜欢
      • 2019-01-12
      • 2018-06-25
      • 1970-01-01
      • 2021-09-21
      • 1970-01-01
      • 2019-06-14
      • 2019-04-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多