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

如何确保TypeScript联合类型在代码中始终保持窄化

问题:如何让TypeScript保持item.args的窄化类型?

我希望通过创建存储所需信息的对象替代大量if语句,让执行流程更线性。以下是示例代码:

type ItemOne = {
  type: 'itemOne'
  fn: typeof funcOne
  args: Parameters<typeof funcOne>[0]
}

type ItemTwo = {
  type: 'itemTwo',
  fn: typeof funcTwo
  args: Parameters<typeof funcTwo>[0]
}

type Item = ItemOne | ItemTwo


function funcOne({ name }: { name: string }) {
  console.log(name)
}

function funcTwo({ age }: { age: number }) {
  console.log(age)
}

function createItem(shouldCreateItemOne: boolean): Item {
  if (shouldCreateItemOne) {
    return { type: 'itemOne', fn: funcOne, args: { name: 'Dave' } } as const
  }

  return { type: 'itemTwo', fn: funcTwo, args: { age: 22  } } as const
}


const item = createItem(false) 

item.fn(item.args)

调用item.fn(item.args)时,TypeScript报错:
Argument of type '{ name: string; } | { age: number; }' is not assignable to parameter of type '{ name: string; } & { age: number; }'.


解决方案

方法1:让createItem返回具体类型(泛型约束)

通过给createItem添加泛型,让TypeScript根据输入参数推断返回的具体Item子类型,而非宽泛的联合类型:

function createItem<T extends boolean>(shouldCreateItemOne: T): T extends true ? ItemOne : ItemTwo {
  if (shouldCreateItemOne) {
    return { type: 'itemOne', fn: funcOne, args: { name: 'Dave' } } as const as any;
  }

  return { type: 'itemTwo', fn: funcTwo, args: { age: 22 } } as const as any;
}

const item = createItem(false); // 类型被推断为ItemTwo
item.fn(item.args); // 无报错

方法2:用类型守卫/switch语句手动窄化类型

通过type字段做分支判断,让TypeScript在每个分支中明确当前item的具体类型,从而正确关联fn和args:

const item = createItem(false);

switch(item.type) {
  case 'itemOne':
    item.fn(item.args); // args被窄化为{ name: string }
    break;
  case 'itemTwo':
    item.fn(item.args); // args被窄化为{ age: number }
    break;
}

方法3:重构类型定义,强关联type、fn和args

用映射类型定义通用的FuncMap,让Item类型自动生成强关联的联合类型,从根源避免类型不匹配:

// 先定义所有函数的映射
type FuncMap = {
  itemOne: typeof funcOne,
  itemTwo: typeof funcTwo
};

// 自动生成关联的Item类型
type Item<T extends keyof FuncMap = keyof FuncMap> = {
  [K in T]: {
    type: K,
    fn: FuncMap[K],
    args: Parameters<FuncMap[K]>[0]
  }
}[T];

// createItem的返回类型会自动推断为正确的子类型
function createItem(shouldCreateItemOne: boolean): Item {
  if (shouldCreateItemOne) {
    return { type: 'itemOne', fn: funcOne, args: { name: 'Dave' } } as const;
  }

  return { type: 'itemTwo', fn: funcTwo, args: { age: 22 } } as const;
}

// 配合条件判断即可正确窄化
const item = createItem(false);
if (item.type === 'itemTwo') {
  item.fn(item.args);
}

报错原因

TypeScript无法自动追踪联合类型中fn和args的对应关系。当直接调用item.fn(item.args)时,它会把fn的参数类型合并为所有可能参数的交集(同时满足funcOne和funcTwo的参数要求),而args是所有可能参数的并集,两者自然无法匹配。通过上述方法,我们让TypeScript明确当前fn对应的具体args类型,从而解决报错。

内容的提问来源于stack exchange,提问作者Kristian Roebuck

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 01:32:49