繁体   English   中英

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

[英]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将泛型类型Kkey参数限制为您的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.

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