如何让TypeScript为NodeDef的compute函数推断正确的依赖参数类型?
解决TypeScript中Graph节点定义的类型推断问题
我需要定义Graph执行框架中的NodeDef类型,用来描述图中的节点。每个NodeDef包含name(节点名)、deps(依赖节点列表)和compute(基于输入计算输出的函数)。要求compute函数的参数对象,只能包含deps中指定的节点对应的Nodes类型值。
当前的类型定义如下:
type Nodes = { a: number; b: number; c: string; }; type Node = keyof Nodes; type NodeDef<N extends Node, D extends Node> = { name: N; deps: D[]; compute: (deps: { [K in D]: Nodes[K] }) => Nodes[N]; }; type Graph = { [K in Node]?: NodeDef<K, Node>; };
但创建Graph实例时,compute函数的参数类型推断不符合预期:
const config: Graph = { a: { name: 'a', deps: ['b'], compute: ({ b, c }) => { // 此处不应允许访问c,但TS未报错 return 2 * b + c.length; }, }, };
期望的推断结果:
(property) compute: (deps: { b: number; }) => number
实际的推断结果:
(property) compute: (deps: { a: number; b: number; c: string; }) => number
问题根源
Graph类型中,NodeDef<K, Node>把泛型参数D固定成了所有Node类型,导致TypeScript无法根据deps的实际值缩小参数范围,只能默认允许所有节点作为compute的参数。
解决方案:使用泛型辅助函数实现自动推断
通过泛型辅助函数让TypeScript自动识别每个节点的具体依赖子集,从而正确约束compute的参数类型:
type Nodes = { a: number; b: number; c: string; }; type Node = keyof Nodes; type NodeDef<N extends Node, D extends Node> = { name: N; deps: D[]; compute: (deps: { [K in D]: Nodes[K] }) => Nodes[N]; }; // 泛型辅助函数,自动推断每个节点的依赖类型 function createGraph<G extends { [K in Node]?: NodeDef<K, any> }>(graph: G): G { return graph; } // 使用辅助函数创建Graph实例,TS会正确约束compute的参数 const config = createGraph({ a: { name: 'a', deps: ['b'], compute: ({ b }) => { // 只能访问b,访问c会触发TS错误 return 2 * b; }, }, c: { name: 'c', deps: ['a', 'b'], compute: ({ a, b }) => { // 只能访问a和b return `${a + b}`; }, }, });
原理说明
- 辅助函数
createGraph的泛型G会根据传入的对象,自动推断每个NodeDef的D参数(即具体的依赖节点子集)。 - 不再直接给实例指定
Graph类型,而是让TypeScript通过泛型推断来约束类型,确保每个节点的deps和compute参数一一对应。
内容的提问来源于stack exchange,提问作者mulles3008
相关产品推荐
相关产品推荐

