TypeScript如何定义递归可变元组类型适配嵌套查询结构
方案1:使用Interface延迟解析(支持无限嵌套,推荐,适配TS 3.7+)
TS 对类型别名的递归解析有严格的立即求值限制,但interface的类型解析是延迟执行的,我们可以借助这个特性绕过循环引用报错:
type IOperator = "AND" | "OR" // 定义子查询结构:强制第一个元素为操作符,后续元素为合法查询单元 interface IQueryClause extends Array<IQuery> { 0: IOperator } // 合法查询 = 检索词(字符串) / 合法子查询 type IQuery = string | IQueryClause
校验所有合法用例均可以正常通过类型检查:
const query1: IQuery = "Hello" // ✅ 合法 const query2: IQuery = ["AND", "Hello", "World"] // ✅ 合法 const query3: IQuery = ["OR", ["AND", "Hello", "World"], ["AND", "Hola", "Mundo"]] // ✅ 合法
非法场景会被正常拦截:
const invalidQuery1: IQuery = ["Hello", "World"] // ❌ 第一个元素不是操作符,报错 const invalidQuery2: IQuery = ["AND", 123] // ❌ 后续元素不是合法查询单元,报错
方案2:有限深度展开(兼容更低版本TS)
如果使用的TS版本不支持上述递归写法,也可以手动展开到业务需要的嵌套深度(一般场景3-5层足够覆盖绝大多数使用需求):
type IOperator = "AND" | "OR" type IQueryDepth0 = string type IQueryDepth1 = IQueryDepth0 | [IOperator, ...IQueryDepth0[]] type IQueryDepth2 = IQueryDepth1 | [IOperator, ...IQueryDepth1[]] type IQueryDepth3 = IQueryDepth2 | [IOperator, ...IQueryDepth2[]] type IQueryDepth4 = IQueryDepth3 | [IOperator, ...IQueryDepth3[]] // 最终使用的类型,支持最多4层嵌套 type IQuery = IQueryDepth4
这种方案没有循环引用问题,兼容更低版本的TS,唯一限制是不支持超过预设深度的无限嵌套。
原写法报错原因
之前的写法触发Type alias 'IQuery' circularly references itself.(2456)错误,是因为TS在解析类型别名时会立即尝试计算类型结构,直接定义递归元组会让TS陷入无限展开的死循环,因此被语法层面拦截。而interface的延迟解析特性可以避开这个限制,实际使用时才会按需校验嵌套结构。
内容的提问来源于stack exchange,提问作者KyleMit
相关产品推荐
相关产品推荐

