简体   繁体   English

TypeScript `string literal` 子集不可分配给重载中的完整集 function

[英]TypeScript `string literal` subsets not assignable to full set in overloaded function

Problem问题

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对我来说有点代码味道)。

End Goal最终目标

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这是让我崩溃的部分

Edits编辑

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将泛型类型Kkey参数限制为您的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!祝你好运!

Playground link to code 游乐场代码链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM