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

如何在TypeScript中对联合类型进行类型收窄?(索引为变量场景)

TypeScript联合类型键检查与类型收窄解决方案

问题背景

你的actionsCollection是由多个结构相似但键集合不同的对象组成的联合类型,示例结构如下:

type ActionsCollection = {
  install: (...args) => Promise<any>;
  bid: (...args) => Promise<any>;
} | {
  travel: (...args) => Promise<any>;
  bid: (...args) => Promise<any>;
  pass: (...args) => Promise<any>;
};

当你通过in、hasOwnProperty等方式检查键是否存在后,TypeScript依然无法正确收窄类型,导致访问actionsCollection[actionType]或特定键时出现类型错误。

解决方法

1. 自定义类型守卫(推荐)

通过**类型谓词(Type Predicate)**手动告诉TypeScript,当前对象属于联合类型中包含指定键的成员:

首先拆分联合类型为单独的类型(便于后续类型收窄):

// 拆分联合类型成员为独立类型
type InstallBidActions = {
  install: (p: DefaultActionParams & { polynominoId: number; polynominoOrientation: number; polynominoPosition: number; }) => Promise<ProcessPlayerActionReturn>;
  bid: (p: DefaultActionParams & { /* 补充你的类型定义 */ }) => Promise<ProcessPlayerActionReturn>;
};

type TravelBidPassActions = {
  travel: (p: DefaultActionParams & { /* 补充你的类型定义 */ }) => Promise<ProcessPlayerActionReturn>;
  bid: (p: DefaultActionParams & { /* 补充你的类型定义 */ }) => Promise<ProcessPlayerActionReturn>;
  pass: (p: DefaultActionParams & { /* 补充你的类型定义 */ }) => Promise<ProcessPlayerActionReturn>;
};

type ActionsCollection = InstallBidActions | TravelBidPassActions;

然后定义通用类型守卫函数:

/**
 * 检查对象是否包含指定键,并让TypeScript完成类型收窄
 */
function hasAction<T extends string>(obj: ActionsCollection, action: T): obj is Extract<ActionsCollection, Record<T, unknown>> {
  return action in obj;
}

在业务代码中替换原有的多重检查:

if (!hasAction(actionsCollection, actionType)) {
  return socket!.emit('socketError', ERRORMESSAGES.UNKNOWNACTION);
}

// 此时TypeScript能正确识别actionsCollection包含actionType对应的键
const ttt = actionsCollection[actionType];

2. 针对特定键的分支收窄

如果需要单独处理某个特定键(比如install),直接用in操作符做分支判断即可,TypeScript会自动收窄类型:

if ('install' in actionsCollection) {
  // 这里actionsCollection会被自动收窄为InstallBidActions类型
  const installAction = actionsCollection.install;
  // 可以安全调用installAction
}

报错原因说明

TypeScript对联合类型的索引操作有严格的类型检查:当你用一个包含多个可能值的联合类型(比如"install" | "bid" | "travel")去索引联合类型时,TS无法确定当前actionsCollection的具体成员是否包含该键,因此会抛出类型错误。而自定义类型守卫通过Extract工具类型,从联合类型中精准提取出包含指定键的成员,让TS明确当前对象的类型范围。

另外,原代码中的Object.keys(actionsCollection).includes(actionType)无法用于类型收窄,因为Object.keys返回的是string[],TS无法将其与具体的键类型关联起来,建议移除这类无效检查。

内容的提问来源于stack exchange,提问作者Jay Dee

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 09:51:25