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

如何用OR运算符筛选TypeScript可辨识联合类型?

TypeScript可辨识联合多类型筛选的类型推断问题

类型定义

type ClipBase = { duration: number; }

type AudioClip = ClipBase & {
    type: "audio"; 
    volume: number;
}

type VideoClip = ClipBase & {
    type: "video"; 
    height: number;
    width: number;
}

type MediaClip = ClipBase & {
    type: "media"; 
    url: string;
}

type Clip =  VideoClip | AudioClip | MediaClip;

现有类型判断辅助函数

export function isType<
  GenericType extends string,
  Union extends { type: GenericType },
  SpecificType extends GenericType,
>(val: SpecificType) {
  return (obj: Union): obj is Extract<Union, { type: SpecificType }> =>
    obj.type === val;
}

单类型筛选(正常推断)

使用isType进行单一类型筛选时,TypeScript能正确推断出结果类型:

function getVideoClips(clips: Clip[]) {
  return clips.filter(isType("video")); // 类型推断为 VideoClip[]
}

多类型筛选(类型推断失败)

但筛选可辨识联合的子集时,TypeScript无法自动推断出正确的联合类型,返回的仍是原类型Clip[]:

function getAudioAndMediaClips(clips: Clip[]) {
  return clips.filter(clip => isType("audio")(clip) || isType("media")(clip)); // 类型推断为 Clip[]
}

解决方案:支持多类型的判断函数

我们可以编写一个支持批量类型判断的辅助函数,无需为每种类型组合单独编写逻辑:

export function isOneOfTypes<
  T extends { type: string },
  K extends T["type"]
>(types: readonly K[]) {
  return (obj: T): obj is Extract<T, { type: K }> =>
    types.includes(obj.type as K);
}

使用示例

function getAudioAndMediaClips(clips: Clip[]) {
  return clips.filter(isOneOfTypes(["audio", "media"])); // 类型推断为 (AudioClip | MediaClip)[]
}

核心逻辑说明

  • 泛型K会捕获传入的所有类型值,通过Extract<T, { type: K }>从原联合类型中提取匹配的成员,生成新的联合类型。
  • 传入只读数组readonly K[]帮助TypeScript更精准地推断泛型参数。
  • obj.type as K是安全的类型断言,因为我们仅验证该值是否在传入的类型数组中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 11:17:05