如何为Flow类创建基于Nodes的动态TypeScript Context类型?
解决方案
要实现让context仅允许节点id作为合法键、值类型匹配对应节点返回值的需求,我们可以利用TypeScript的泛型与映射类型来实现类型约束与自动推导:
1. 定义工具类型提取Context结构
先创建一个工具类型,从节点数组类型中自动推导context的键值对结构:
// 从节点数组类型中提取context的键值映射类型 type ContextFromNodes<Nodes extends Node<any>[]> = { [NodeType in Nodes[number] as NodeType['id']]: NodeType['result']; };
这个类型会遍历数组中的每个节点,将节点的id作为键,result类型作为对应的值类型。
2. 修改Flow类为泛型类
将Flow改为泛型类,接收节点数组类型作为泛型参数,同时把context的类型绑定到上面的工具类型:
export class Node<T extends (...args: any[]) => any> { id: string; action: T; result: ReturnType<T>; constructor(id: string, action: T) { this.id = id; this.action = action; } } export class Flow<Nodes extends Node<(flow: Flow<Nodes>) => any>[]> { nodes: Nodes; context: ContextFromNodes<Nodes>; constructor(nodes: Nodes) { this.nodes = nodes; // 初始化context并执行节点动作填充值 this.context = {} as ContextFromNodes<Nodes>; nodes.forEach(node => { const result = node.action(this); node.result = result; // 同步更新Node的result属性(可选) this.context[node.id as keyof ContextFromNodes<Nodes>] = result; }); } }
3. 验证效果
现在你的示例代码会完全符合预期:
const flow = new Flow([ new Node("one", () => 1), new Node("two", (flow) => flow.context.one + 1), ]); flow.context.one; // 类型为number,运行时值为1 flow.context.asdasd; // TypeScript报错:该类型不存在"asdasd"属性
关键说明
- 泛型
Nodes让TypeScript能精确推断传入节点数组中每个节点的id和返回值类型; ContextFromNodes通过类型重映射,将节点数组转换为context的结构类型,实现键的合法性约束;- 构造函数中遍历节点并执行
action,确保context在运行时被正确填充,同时类型层面严格匹配。
内容的提问来源于stack exchange,提问作者Truman Purnell
相关产品推荐
相关产品推荐

