TypeScript中如何定义关联同对象内其他属性键的接口或类型?
TypeScript中约束对象属性键为另一属性键的子集
需求说明
需要定义Graph类型,让connections的键必须是nodes属性键的子集,当connections使用nodes中不存在的键时,TypeScript能抛出错误。基础的Node和Connection接口如下:
interface Node { id: string; // ...其他无关属性 } interface Connection { fromNode: string; toNode: string; // ...其他无关属性 }
原有的Graph接口无法实现该约束:
interface Graph { nodes: Record<string, Node> connections: Record<string, Connection> // 其他无关属性 }
解决方案
要实现这种同一对象内属性键的依赖约束,不能用普通接口,需要借助泛型类型来捕获nodes的具体键集合,然后约束connections的键只能是这个集合的子集。
泛型Graph类型定义
type Graph<NodeKey extends string> = { nodes: Record<NodeKey, Node>; connections: Partial<Record<NodeKey, Connection>>; // 其他无关属性可以在这里添加 };
使用示例
当创建具体的Graph对象时,TypeScript会自动推断NodeKey的类型,从而约束connections的键:
// 正确示例:connections的键都是nodes的键子集 const validGraph: Graph<"nodeA" | "nodeB"> = { nodes: { "nodeA": { id: "nodeA" }, "nodeB": { id: "nodeB" } }, connections: { "nodeA": { fromNode: "nodeA", toNode: "nodeB" } } }; // 错误示例:connections使用了nodes中不存在的"nodeC",TypeScript会报错 const invalidGraph: Graph<"nodeA" | "nodeB"> = { nodes: { "nodeA": { id: "nodeA" }, "nodeB": { id: "nodeB" } }, connections: { "nodeC": { fromNode: "nodeA", toNode: "nodeB" } // 此处会报错:类型“"nodeC"”的属性不能赋给类型“"nodeA" | "nodeB"”的索引类型 } };
自动推断泛型参数
如果不想手动指定NodeKey,可以创建一个辅助函数让TypeScript自动推断:
function createGraph<NodeKey extends string>(graph: Graph<NodeKey>) { return graph; } // 自动推断NodeKey为"nodeA" | "nodeB" const autoGraph = createGraph({ nodes: { "nodeA": { id: "nodeA" }, "nodeB": { id: "nodeB" } }, connections: { "nodeA": { fromNode: "nodeA", toNode: "nodeB" } } }); // 错误示例:connections使用"nodeC"会报错 const autoInvalidGraph = createGraph({ nodes: { "nodeA": { id: "nodeA" }, "nodeB": { id: "nodeB" } }, connections: { "nodeC": { fromNode: "nodeA", toNode: "nodeB" } // 报错 } });
补充说明
- 使用
Partial<Record<NodeKey, Connection>>是为了允许connections只包含nodes键的一部分,如果你要求connections必须包含所有nodes的键,可以去掉Partial,直接用Record<NodeKey, Connection>。 - 这种方式完美适配运行时生成的UUID场景,只要创建对象时TypeScript能捕获到
nodes的键集合,就能自动完成约束。
内容的提问来源于stack exchange,提问作者Rumpelstinsk
相关产品推荐
相关产品推荐

