在TypeScript中使用映射类型时更严格的联合类型

时间:2018-08-21 16:51:29

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

我试图在映射中使用联合类型时使用映射类型来提供更多类型安全性。使用属性类型(例如['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的{​​{1}}实现,我想避免这种情况。

在当前版本的TypeScript中这可能吗?

1 个答案:

答案 0 :(得分:1)

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

您注意到,您的问题是ActionMapper<A>的属性值始终为A。对于Actions,这是联合类型。您真正想做的是从A中提取与每个键{value: K}匹配K的成分。幸运的是,有一个名为pre-defined conditional typeExtract可以为您完成此任务。让我们重新定义ActionMapper<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"'.
}

然后您得到预期的错误。希望能有所帮助。祝你好运!