[英]TypeScript `string literal` subsets not assignable to full set in overloaded function
Trying to create a mapping function for typed key-value pairs:尝试为键入的键值对创建映射 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 {};
}
Later on I try to use this mapping function, but with a subset of the Color
type稍后我尝试使用此映射 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));
However, on the call to map(fruit)
I get the following error:但是,在调用
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"'.
Seems odd to me since the fruit
parameter is a subset of the possible fruits that could be passed in. Having trouble making this mapping function overload work without using the as
keyword (needing as
is a bit of code-smell to me).对我来说似乎很奇怪,因为
fruit
参数是可以传入的可能 fruits 的子集。在不使用as
关键字的情况下无法使此映射 function 重载工作(需要as
对我来说有点代码味道)。
I would like to be able to reconstruct Color
from one or more Partial<Color>
s.我希望能够从一个或多个
Partial<Color>
重建Color
。 For instance, say I do this:例如,假设我这样做:
const redGreen = map("Apple");
const yellowGreen = map("Banana");
const purpleGreen = map("Grape");
const allColors: Color = {
...redGreen,
...yellowGreen,
...purpleGreen
};
The above works as TypeScript can infer that the aggregated Color
object's properties are all there.上面的工作原理为 TypeScript 可以推断聚合的
Color
对象的属性都在那里。 However, I'd like to maintain the ability to also aggregate Partial<Color>
objects as show in the example above:但是,我想保持聚合
Partial<Color>
对象的能力,如上例所示:
const colors: Partial<Color>[] = fruits.map(fruit => map(fruit));
This is the part that breaks for me这是让我崩溃的部分
EDIT: Changed Color
to be an object to better model my situation (and make it easier for others to copy-paste into their own IDEs编辑:将
Color
更改为 object 以改善 model 我的情况(并使其他人更容易复制粘贴到他们自己的 IDE 中
EDIT2: Fixing overload return types EDIT2:修复重载返回类型
EDIT3: (keyof Pick<PropMapping, "Apple" | "Banana">)[]
...oh gosh. EDIT3:
(keyof Pick<PropMapping, "Apple" | "Banana">)[]
...哦天哪。 Thanks everyone for pointing these out谢谢大家指出这些
TypeScript does not support calling multiple overload signatures at the same time. TypeScript 不支持同时调用多个重载签名。 It is conceivable that the compiler could support resolving such calls by allowing unions of the arguments and then returning a union of the return types, but this is not a feature, at least for now.
可以想象,编译器可以通过允许 arguments 的并集然后返回返回类型的并集来支持解析此类调用,但这不是一个功能,至少目前如此。 See microsoft/TypeScript#14107 for an open suggestion for this sort of support.
有关此类支持的公开建议,请参阅microsoft/TypeScript#14107 。
Unless and until this is supported, you'll need to refactor your code if you want the compiler to understand this sort of call.除非并且直到它得到支持,否则如果您希望编译器理解这种调用,则需要重构您的代码。 You could add a call signature for each possible expected set of parameters, but that's only feasible for a small number of initial overload sets, since if you start with n disjoint call signatures you'd end up with 2 n merged signatures.
您可以为每个可能的预期参数集添加一个调用签名,但这仅适用于少数初始重载集,因为如果您从n 个不相交的调用签名开始,您最终会得到 2 n 个合并的签名。
For the particular example code you've posted where you are mapping keys to value types, by far the most straightforward solution is to abandon overloads (or at least abandon multiple call signatures) in favor of a generic function, like this:对于您发布的将键映射到值类型的特定示例代码,到目前为止,最直接的解决方案是放弃重载(或至少放弃多个调用签名)以支持通用function,如下所示:
function map2<K extends keyof PropMapping>(key: K): PropMapping[K];
function map2(key: keyof PropMapping): Color {
return null!;
}
Here, map2
takes a key
parameter of generic type K
constrained to be a key of your PropMapping
type, and it returns PropMapping[K]
, the type of the value you get when you look up the K
key in a PropMapping
object.在这里,
map2
将泛型类型K
的key
参数限制为您的PropMapping
类型的键,并返回PropMapping[K]
,即您在PropMapping
object 中查找K
键时获得的值的类型。
Then your array call should work:然后你的数组调用应该工作:
const colors = fruits.map(fruit => map2(fruit));
// const colors: (Pick<Color, "Red" | "Green"> | Pick<Color, "Green" | "Yellow">)[]
Okay, hope that helps;好的,希望有所帮助; good luck!
祝你好运!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.