TypeScript 循环元组数组

not*_*rig 11 typescript

如何在 TypeScript 中循环元组数组?例如

for (const [x, y] of [['a', 1], ['b', 2]]) {
  y + 1;
}
Run Code Online (Sandbox Code Playgroud)

抱怨:

error TS2365: Operator '+' cannot be applied to types 'string | number' and '1'.
Run Code Online (Sandbox Code Playgroud)

如果我理解正确的话,TypeScript 会推断(string | number)[][]循环表达式的类型,这就是为什么循环变量y具有类型string | number,尽管实际上它只能具有类型number

我认为https://github.com/microsoft/TypeScript/issues/3369是阻止 TypeScript 推断合适类型的问题。循环元组数组的当前解决方案是什么?类型断言?

Ali*_*deh 9

只需添加 TS 应该理解结构的类型注释即可。它还不能从集合中推断出来。

const array: [string, number][] = [['a', 1], ['b', 2]];

for (const [x, y] of array) {
  y + 1;
}
Run Code Online (Sandbox Code Playgroud)

另外我想提一下,在处理二维关联时,我认为更好的数据结构是 Map:

const myMap = new Map<string, number>([['a', 1], ['b', 2]]);

for (const [x, y] of [...myMap]) {
  console.log(y + 1);
}
Run Code Online (Sandbox Code Playgroud)

高级:自定义迭代

如果元组的逻辑是一致的,那么您可以使用Symbol.iterator著名的符号创建自己的可迭代对象:

class TupleMaker implements Iterable<[string, number]> {
  private next = 0;
  constructor(private endsAt: number = 0) {}

  private increment(): void {
    this.next++;
  }

  *[Symbol.iterator](): Generator<[string, number]> {
    const alpha = Array.from(Array(26)).map((e, i) => i + 65);
    const alphabet = alpha.map((x) => String.fromCharCode(x).toLocaleLowerCase());
    while (this.next < this.endsAt) {
      yield [alphabet[this.next], this.next + 1];
      this.increment();
    }
  }
}

for (const [x, y] of new TupleMaker(13)) {
  console.log(y + 1);
}
Run Code Online (Sandbox Code Playgroud)

它们也可以是异步的,使用Symbol.asyncIterator


Tit*_*mir 5

真正的问题是 的类型[['a', 1], ['b', 2]]根本不是元组类型。它将是数组类型(string | number)[][]。所以解构时xy都会是string | number。Typescript 只会在特定情况下推断元组(例如约束为数组的类型参数或断言as const)。

如果您使用as const断言来获取打字稿来推断元组类型,并且一切都会按预期工作:

for (const [x, y] of [['a', 1], ['b', 2]] as const) {
  y + 1;
}

Run Code Online (Sandbox Code Playgroud)