You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何断言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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 01:22:19