尝试返回 Map 时“没有重载匹配此调用”

时间:2021-05-17 14:34:08

标签: typescript dictionary

在尝试创建地图时,我收到一个我不太明白的奇怪错误:

TS2769: No overload matches this call.
  Overload 1 of 4, '(iterable: Iterable<readonly [string, number]>): Map<string, number>', gave the following error.
    Argument of type '(string | number)[][]' is not assignable to parameter of type 'Iterable<readonly [string, number]>'.
      The types returned by '[Symbol.iterator]().next(...)' are incompatible between these types.
        Type 'IteratorResult<(string | number)[], any>' is not assignable to type 'IteratorResult<readonly [string, number], any>'.

在我的代码中,我接受了一个数组并尝试构造它的映射对象

function createMapOfHeadersToIndex(headers: string[]): Map<string, number> {
  const headersWithIndex =
      headers.map(header => [header, Number(headers.indexOf(header))]);
  return new Map(headersWithIndex);
}

1 个答案:

答案 0 :(得分:1)

由于您没有 annotate 的类型 headersWithIndex,编译器根据人们倾向于使用数组的启发式规则为您推断它的类型:

const headersWithIndex =
  headers.map(header => [header, Number(headers.indexOf(header))]);
// const headersWithIndex: (string | number)[][]

该类型,(string | number)[][] 表示“由 stringnumber 元素组成的数组”。这并不是对 headersWithIndex 的错误描述,在其他情况下,您可以合理猜测您可能会用它做什么:

headersWithIndex.push([1, "two", 3, "four"]); // okay

不幸的是,该类型不够具体,无法被 Map 构造函数接受,该构造函数期望一个可迭代对象,其元素显式为键的 2-{{​​3}} 后跟一个值。因此构造调用失败,因为编译器忘记了有关 headersWithIndex 元素内数组的特定顺序和长度的任何信息。


解决此问题的最直接方法是在创建包含键和值的数组文字时使用 tuple

const headersWithIndex =
  headers.map(header => [header, Number(headers.indexOf(header))] as const);
// const headersWithIndex: (readonly [string, number])[]
return new Map(headersWithIndex); //okay

那个 as const 给编译器一个提示,你希望它推断出它所能推断的最具体的类型;这几乎就像在说“我不会改变这个东西的内容,所以请注意一切的确切位置”。你会看到现在 headersWithIndex 被推断为类型 (readonly [string, number])[];也就是说,由一个 string 和一个 number 组成的 const assertion 数组。

现在 Map 构造函数很高兴,因为它肯定知道 headersWithIndex 的每个元素都是一对 string 键和 number 值,结果在 Map<string, number> 中。

readonly tuples