如何断言TypeScript中两个联合类型变量类型一致?
问题描述
我需要更新不同类型节点的data字段:传入的data类型确定但不固定,而nodes的类型固定为FlowNode联合类型数组。目前通过逐个判断节点类型的方式可以实现,但我不想为每个节点类型都写断言逻辑,希望找到更通用的写法。
原始代码
export type Node< NodeData extends Record<string, unknown> = Record<string, unknown>, NodeType extends string = string > = { id: string; data: NodeData; type: NodeType; }; export type SourceNode = Node< { current: string; }, "source" >; export type TargetNode = Node< { targetType: number; }, "target" >; export function isRuleNode(node: FlowNode): node is RuleNode { return node.type === "rule"; } export type RuleNode = Node< { ruleName: string; }, "rule" >; export type FilterNode = Node< { name: string; }, "filter" >; export type FlowNode = | RuleNode | FilterNode | SourceNode | TargetNode function updateNodeData(nodes: FlowNode[], data: Partial<FlowNode["data"]>) { // if the union type is the same? nodes = nodes.map((node) => { // problem is here return { ...node, data: { ...node.data, ...data, }, }; }); return nodes; } // RuleNode here can be changed let data: Partial<RuleNode["data"]> = { ruleName: "test", }; let nodes: FlowNode[] = []; // type here cannot be changed updateNodeData(nodes, data);
当前可行但不希望使用的写法
nodes = nodes.map((node) => { if (isRuleNode(node)) { return { ...node, data: { ...node.data, ...data, } } } return node })
解决方案
可以通过泛型约束+类型守卫工厂函数实现通用的类型匹配,无需逐个编写断言逻辑:
1. 通用类型守卫工厂
创建一个能根据节点类型字符串生成对应类型守卫的函数,避免为每个节点单独写isRuleNode这类函数:
function isNodeOfType<T extends FlowNode>(type: T["type"]) { return (node: FlowNode): node is T => node.type === type; }
2. 改造为泛型更新函数
让函数接收节点类型标识和对应的数据类型,自动匹配需要更新的节点:
function updateNodeData<T extends FlowNode>( nodes: FlowNode[], nodeType: T["type"], data: Partial<T["data"]> ) { const isTargetNode = isNodeOfType<T>(nodeType); return nodes.map(node => { if (isTargetNode(node)) { return { ...node, data: { ...node.data, ...data } }; } return node; }); }
使用示例
// 更新RuleNode类型的节点 const updatedNodes = updateNodeData(nodes, "rule", { ruleName: "test" }); // 更新FilterNode类型的节点 updateNodeData(nodes, "filter", { name: "new-filter" });
原理说明
- 泛型
T会根据传入的nodeType自动推导对应的具体节点类型(比如传入"rule"就推导为RuleNode) - 工厂函数
isNodeOfType生成对应类型的守卫,确保只有匹配类型的节点才会被更新 - 新增节点类型时无需额外编写类型守卫函数,只需维护一套核心逻辑
内容的提问来源于stack exchange,提问作者Evilolipop
相关产品推荐
相关产品推荐

