TypeScript中循环引用类型的无深度限制惰性求值点表示法路径校验与智能提示实现问询
TypeScript中循环引用类型的无深度限制惰性求值点表示法路径校验与智能提示实现问询
我现在在实现一个点表示法路径的类型校验工具,但遇到了两个核心的棘手问题,想请教大家有没有更好的解决方案。
先说说我的类型基础定义,这里有两个循环引用的类型:
type Message = { content: string; owner: Owner; }; type Owner = { email: string; ownedMessages: Message[]; };
需求说明
我要实现的路径校验工具,需要满足以下的有效/无效路径规则:
有效路径示例
"messages""messages.content""messages.owner""messages.owner.email""messages.owner.ownedMessages""messages.owner.ownedMessages.content"- 理论上支持无限嵌套,比如
messages.owner.ownedMessages.owner.ownedMessages...这种层级可以无限延伸的路径
无效路径示例
- 拼写错误的路径,比如
messages.emaill、messages.foo、messages.ownerr - 指向不存在属性的路径,比如
messages.owner.foo
核心约束
我有两个特别在意的约束条件,希望实现的方案能满足:
- 无深度限制:优先支持无限层级的路径嵌套,实在没办法才考虑加深度限制
- 惰性智能提示:希望TypeScript的智能提示是“懒加载”的:
- 当用户输入
messages.时,只提示content和owner两个属性 - 当用户输入
messages.owner.时,只提示email和ownedMessages两个属性 - 而不是一开始就把所有可能的深层嵌套路径都列出来,避免智能提示过于杂乱
- 当用户输入
我目前的实现方案(存在缺陷)
我自己尝试写了一个方案,但它有两个明显的问题:有深度限制,而且是提前计算所有可能路径的(非惰性)。下面是我的实现代码:
type Message = { content: string; owner: Owner; }; type Owner = { email: string; ownedMessages: Message[]; }; // 问题1:必须依赖这个数组来指定最大深度 type Prev = [never, 0, 1, 2, 3, 4, 5]; type DotNotationPaths<T, MaxDepth extends number = 5> = MaxDepth extends 0 ? never : T extends object ? { [K in keyof T & string]: T[K] extends Array<infer U> ? K | `${K}.${DotNotationPaths<U, Prev[MaxDepth]>}` : T[K] extends object ? K | `${K}.${DotNotationPaths<T[K], Prev[MaxDepth]>}` : K; }[keyof T & string] : never; type ValidMessagePath = "messages" | `messages.${DotNotationPaths<Message>}`; // 符合预期的有效路径测试 const validPath1: ValidMessagePath = "messages.content"; // ✓ const validPath2: ValidMessagePath = "messages.owner"; // ✓ const validPath3: ValidMessagePath = "messages.owner.email"; // ✓ const validPath4: ValidMessagePath = "messages.owner.ownedMessages"; // ✓ const validPath5: ValidMessagePath = "messages.owner.ownedMessages.content"; // ✓ const validPath6: ValidMessagePath = "messages.owner.ownedMessages.owner.email"; // ✓ const validPath7: ValidMessagePath = "messages"; // ✓ // 符合预期的无效路径报错 // @ts-expect-error const invalidPath1: ValidMessagePath = "messages.contentt"; // ✗ // @ts-expect-error const invalidPath2: ValidMessagePath = "messages.owner.emailll"; // ✗ // @ts-expect-error const invalidPath3: ValidMessagePath = "messages.ownerr"; // ✗
这个方案的缺陷很明显:
- 必须通过
Prev数组和MaxDepth参数限制最大嵌套深度,没办法支持真正的无限层级 - 它会提前计算所有可能的嵌套路径,导致智能提示一开始就把所有层级的属性都列出来,完全不符合我想要的“惰性提示”需求
我了解到ArkType这类工具似乎能实现这种惰性的无限嵌套路径提示,但不知道具体是怎么用TypeScript类型系统实现的。想请教大家,有没有办法实现满足我这两个核心约束的路径校验工具?
内容来源于stack exchange
相关产品推荐
相关产品推荐

