根据映射键从接口映射中选择类型
Picking a type from an interface map based on map key
我想编写一个通用的创建方法来生成在地图中输入的不同对象。问题是 typescript 将所有接口混合在一起,而不是只在接口映射中选择一个:
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'};
}
}
这里有两个问题。
首先,TypeScript 并没有基于类型保护来缩小泛型的定义。这是一种已知和预期的行为,尽管它可能令人沮丧。当你检查 if (id === 'a')
时,typescript 知道变量 id
的值是 A
类型。然而,它并没有将通用范围缩小到 A
。泛型 ID
是联合 A | B
并且变量 id
是 A
是完全有效的。因此,当该检查通过时,我们知道 ID
必须包含 A
,但我们不知道它是“A
且仅包含 A
”。
第二个问题是为什么类型 ABMap[ID]
缩小为 A & B
而不是 A | B
。那个我无法解释。
有(至少)三个解决方案。
您可以做您所做的,将 return 类型扩展为 ABMap[keyof ABMap]
又名 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'};
}
}
- 您可以保留您的泛型并通过使用
as
关键字告诉打字稿您正在 return 实际上是正确的类型。
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];
}
}
我想编写一个通用的创建方法来生成在地图中输入的不同对象。问题是 typescript 将所有接口混合在一起,而不是只在接口映射中选择一个:
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'};
}
}
这里有两个问题。
首先,TypeScript 并没有基于类型保护来缩小泛型的定义。这是一种已知和预期的行为,尽管它可能令人沮丧。当你检查 if (id === 'a')
时,typescript 知道变量 id
的值是 A
类型。然而,它并没有将通用范围缩小到 A
。泛型 ID
是联合 A | B
并且变量 id
是 A
是完全有效的。因此,当该检查通过时,我们知道 ID
必须包含 A
,但我们不知道它是“A
且仅包含 A
”。
第二个问题是为什么类型 ABMap[ID]
缩小为 A & B
而不是 A | B
。那个我无法解释。
有(至少)三个解决方案。
您可以做您所做的,将 return 类型扩展为
ABMap[keyof ABMap]
又名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'};
}
}
- 您可以保留您的泛型并通过使用
as
关键字告诉打字稿您正在 return 实际上是正确的类型。
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];
}
}