如何定义包含指定元素的TypeScript数组类型并解决循环引用报错?
问题描述
我该如何编写TypeScript类型约束,要求数组中必须存在某个指定元素?举个例子,我需要定义"至少包含一个数字7的数字数组",看起来要求某一个固定位置的元素为7很容易,但要求"数组中任意一个元素为7"的实现难度更高。
我尝试了如下实现方案,但是抛出了Type alias 'ContainsSeven' circularly references itself. ts(2456)错误:
type ContainsSeven = |[7, ...Array<number>] |[number, ...ContainsSeven] const example1: ContainsSeven = [1,2,7] const example2: ContainsSeven = [1,7,2] const example3: ContainsSeven = [7,1,2] // @ts-expect-error const counter1: ContainsSeven = [] // @ts-expect-error const counter2: ContainsSeven = [1,2,3]
我的最终目标是使用标准JavaScript Array而非自定义链表结构来实现生成器的惰性拼接。
解决方案
错误原因
原有写法触发了TypeScript的类型别名循环引用检测规则:TypeScript不允许类型别名直接在自身定义的顶层结构中作为元组展开项引用自身,因此会抛出2456错误。
通用实现(支持任意长度数组)
可以通过尾递归条件类型实现,该形式会被TypeScript类型检测器特殊处理,不会触发循环报错:
// 通用泛型工具:约束数组T中必须包含类型为U的元素 type Contains<T extends any[], U> = T extends [infer Head, ...infer Tail] ? Head extends U ? T : Contains<Tail, U> : never // 定义「至少包含一个7的数字数组」类型 type ArrayWithSeven = Contains<number[], 7> // 测试用例 const example1: ArrayWithSeven = [1,2,7] // 类型校验通过 const example2: ArrayWithSeven = [1,7,2] // 类型校验通过 const example3: ArrayWithSeven = [7,1,2] // 类型校验通过 // @ts-expect-error 空数组不符合要求 const counter1: ArrayWithSeven = [] // @ts-expect-error 数组中不存在7不符合要求 const counter2: ArrayWithSeven = [1,2,3]
短数组简化实现
如果使用场景中数组长度不会超过固定值,也可以用枚举位置的写法,可读性更高:
type ArrayWithSeven = | [7, ...number[]] | [number, 7, ...number[]] | [number, number, 7, ...number[]] // 按需扩展到你需要的最大数组长度即可
内容的提问来源于stack exchange,提问作者cyberixae
相关产品推荐
相关产品推荐

