[英]TypeScript `string literal` subsets not assignable to full set in overloaded function
尝试为键入的键值对创建映射 function:
type Color = {
"Red": number,
"Green": string
"Yellow": boolean
"Purple": object
};
type PropMapping = {
"Apple": Pick<Color, "Red" | "Green">,
"Banana": Pick<Color, "Yellow" | "Green">,
"Grape": Pick<Color, "Purple" | "Green">
}
function map(key: "Apple"): Pick<Color, "Red" | "Green">;
function map(key: "Banana"): Pick<Color, "Yellow" | "Green">;
function map(key: "Grape"): Pick<Color, "Purple" | "Green">;
function map(key: keyof PropMapping): Partial<Color> {
// perform actual mapping in here (e.g. via switch-case)
return {};
}
稍后我尝试使用此映射 function,但使用Color
类型的子集
// type of fruits is a subset of `keyof PropMapping`
const fruits: (keyof Pick<PropMapping, "Apple" | "Banana">)[] = ["Apple", "Banana", "Banana"];
// call the mapping function on each fruit
const colors: Partial<Color>[] = fruits.map(fruit => map(fruit));
但是,在调用map(fruit)
时出现以下错误:
No overload matches this call.
The last overload gave the following error.
Argument of type '"Apple" | "Banana"' is not assignable to parameter of type '"Grape"'
Type '"Apple"' is not assignable to type '"Grape"'.
对我来说似乎很奇怪,因为fruit
参数是可以传入的可能 fruits 的子集。在不使用as
关键字的情况下无法使此映射 function 重载工作(需要as
对我来说有点代码味道)。
我希望能够从一个或多个Partial<Color>
重建Color
。 例如,假设我这样做:
const redGreen = map("Apple");
const yellowGreen = map("Banana");
const purpleGreen = map("Grape");
const allColors: Color = {
...redGreen,
...yellowGreen,
...purpleGreen
};
上面的工作原理为 TypeScript 可以推断聚合的Color
对象的属性都在那里。 但是,我想保持聚合Partial<Color>
对象的能力,如上例所示:
const colors: Partial<Color>[] = fruits.map(fruit => map(fruit));
这是让我崩溃的部分
编辑:将Color
更改为 object 以改善 model 我的情况(并使其他人更容易复制粘贴到他们自己的 IDE 中
EDIT2:修复重载返回类型
EDIT3: (keyof Pick<PropMapping, "Apple" | "Banana">)[]
...哦天哪。 谢谢大家指出这些
TypeScript 不支持同时调用多个重载签名。 可以想象,编译器可以通过允许 arguments 的并集然后返回返回类型的并集来支持解析此类调用,但这不是一个功能,至少目前如此。 有关此类支持的公开建议,请参阅microsoft/TypeScript#14107 。
除非并且直到它得到支持,否则如果您希望编译器理解这种调用,则需要重构您的代码。 您可以为每个可能的预期参数集添加一个调用签名,但这仅适用于少数初始重载集,因为如果您从n 个不相交的调用签名开始,您最终会得到 2 n 个合并的签名。
对于您发布的将键映射到值类型的特定示例代码,到目前为止,最直接的解决方案是放弃重载(或至少放弃多个调用签名)以支持通用function,如下所示:
function map2<K extends keyof PropMapping>(key: K): PropMapping[K];
function map2(key: keyof PropMapping): Color {
return null!;
}
在这里, map2
将泛型类型K
的key
参数限制为您的PropMapping
类型的键,并返回PropMapping[K]
,即您在PropMapping
object 中查找K
键时获得的值的类型。
然后你的数组调用应该工作:
const colors = fruits.map(fruit => map2(fruit));
// const colors: (Pick<Color, "Red" | "Green"> | Pick<Color, "Green" | "Yellow">)[]
好的,希望有所帮助; 祝你好运!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.