根据映射键从接口映射中选择类型
Posted
技术标签:
【中文标题】根据映射键从接口映射中选择类型【英文标题】:Picking a type from an interface map based on map key 【发布时间】:2021-02-03 10:28:31 【问题描述】:我想编写一个通用的创建方法,该方法可以生成在地图中输入的不同对象。问题是打字稿将所有接口混合在一起,而不是只在接口映射中选择一个:
interface A
a: string;
interface B
b: string;
interface ABMap
a: A;
b: B;
function create<ID extends keyof ABMap>(id: ID): ABMap[ID] // this is now combined A & B instead of A | B
if (id === 'a')
return a: 'a'; // error a is missing b key
else if (id === 'b')
return b: 'b';
【问题讨论】:
问题似乎是if语句没有缩小id
的类型,它仍然在分支中有ID extends "a" | "b"
类型。
我目前已使用此帮助程序 type ValueOf<T> = T[keyof T];
修复了错误,然后返回 ValueOf<ABMap>
。但也许有更好的解决方案。
这里是一个issue mentioning the problem,虽然ID & 'a'
类型可能也没有帮助,但需要将其缩小为'a'
。
另外,问题有点像***.com/questions/60204107/…
【参考方案1】:
这里有两个问题。
首先,typescript 不会根据类型保护来缩小泛型的定义。这是一种已知和预期的行为,尽管它可能令人沮丧。当您检查if (id === 'a')
时,typescript 知道变量id
的值是A
类型。然而,它并没有将泛型缩小到仅A
。泛型类型ID
是联合A | B
和变量id
是A
是完全有效的。所以当检查通过时,我们知道ID
必须包含A
,但我们不知道它是“A
并且只有A
”。
第二个问题是为什么ABMap[ID]
类型会缩小为A & B
而不是A | B
。那个我无法解释。
有(至少)三种解决方案。
你可以做你所做的,将返回类型扩大到ABMap[keyof ABMap]
aka A | B
如果您正在处理一小组配对,例如本例中的两个,您可以通过函数重载来关联输入和输出:
function create(id: 'a'): ABMap['a']
function create(id: 'b'): ABMap['b']
function create(id: keyof ABMap): ABMap[keyof ABMap]
if (id === 'a')
return a: 'a';
else
return b: 'b';
-
您可以保留泛型并告诉 typescript 您返回的内容实际上是正确的类型,方法是使用
as
关键字。
function create<ID extends keyof ABMap>(id: ID): ABMap[ID]
if (id === 'a')
return a: 'a' as ABMap[ID];
else
return b: 'b' as ABMap[ID];
Playground Link
【讨论】:
以上是关于根据映射键从接口映射中选择类型的主要内容,如果未能解决你的问题,请参考以下文章