首页 > 解决方案 > 在 TypeScript 中使用映射类型时更严格的联合类型

问题描述

在映射中使用联合类型时,我正在尝试使用映射类型来提供更多类型安全性。['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,它提供了is 类型的IAction实现——我想避免这种情况。valuestring

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

标签: typescripttypesdiscriminated-unionunion-typesmapped-types

解决方案


是的,可以做你想做的事。

正如您所注意到的,您的问题是属性的值ActionMapper<A>总是A。对于Actions,这是一个联合类型。您真正想要做的是从与每个 keyA匹配的成分中提取。幸运的是,有一个名为的预定义条件类型可以为您执行此操作。让我们重新定义:{value: K}KExtractActionMapper<A>

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"'.
}

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


推荐阅读