TypeScript如何指定Iterator返回元组类型 解决展开参数报错问题
解决方案
核心思路是让TypeScript识别到你的类迭代器和元组[number, number]的迭代器类型完全一致,携带固定长度为2的类型信息,具体有两种实现方式:
方案1:直接复用元组迭代器(推荐)
不使用生成器语法,直接返回components属性本身的迭代器,同时显式声明方法返回类型为元组的迭代器类型:
class Vector2 { components: [number, number] constructor(x: number, y: number) { this.components = [x, y] } // 直接复用[number, number]元组的迭代器类型,自带长度信息 [Symbol.iterator](): [number, number][Symbol.iterator] { return this.components[Symbol.iterator]() } }
方案2:生成器语法加类型断言
如果你需要保留生成器的写法,可以手动对生成器返回值做类型断言:
class Vector2 { components: [number, number] constructor(x: number, y: number) { this.components = [x, y] } *[Symbol.iterator]() { yield* this.components // 断言为元组迭代器类型 } as unknown as [number, number][Symbol.iterator] }
修改完成后,你原先的展开操作就可以正常通过类型校验:
declare var ctx: CanvasRenderingContext2D // 无报错,TS识别到两个Vector2展开后共4个参数,符合strokeRect的参数要求 ctx.strokeRect(...new Vector2(1,1), ...new Vector2(1,1))
原理解释
- TypeScript对普通数组和元组的迭代器做了类型区分:元组的迭代器携带了固定长度的信息,而普通数组的迭代器只有元素类型信息,没有长度信息
- 生成器函数的默认类型推导只会识别产出值的类型,不会携带长度信息,默认推导出来的迭代器类型对应
number[],无法满足参数展开时的固定长度校验要求 - 直接复用元组本身的迭代器类型,就可以把长度信息传递给类的迭代器,TS就能正确识别展开后的参数数量
内容的提问来源于stack exchange,提问作者Jonas Røssum
相关产品推荐
相关产品推荐

