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

TypeScript中如何实现模式匹配?有哪些推荐方案?

你提到的带tag的联合类型+switch/case确实是TypeScript里实现模式匹配的标准入门方案——毕竟TS本身没有原生的模式匹配语法,这种方式靠类型系统就能保证类型安全。不过确实,写多了switch会有点繁琐,这里给你几个更友好的方案,从原生优化到第三方工具都有:

1. 优化原生Switch方案:加上穷尽检查,避免遗漏Case

你的基础写法已经没问题,但可以加个穷尽检查来避免新增联合类型成员时忘记处理的问题。通过never类型的断言,TypeScript会在你漏写case时直接报错:

interface First { tag: 'one', value: number }
interface Second { tag: 'two', text: string }
type Third = First | Second

function matchThird(input: Third): string {
  switch(input.tag) {
    case 'one':
      // TypeScript自动推断input为First类型,可直接访问value
      return `Number value: ${input.value}`;
    case 'two':
      return `Text value: ${input.text}`;
    default:
      // 新增Third成员时,input无法赋值给never,直接报错
      const _exhaustiveCheck: never = input;
      throw new Error(`Unexpected tag: ${_exhaustiveCheck}`);
  }
}

2. 封装函数式Match工具,让写法更声明式

如果你觉得switch不够优雅,可以自己封装一个通用的match函数,把各个tag的处理逻辑作为参数传入,写法更接近函数式的模式匹配:

// 定义匹配规则类型:每个tag对应一个处理函数
type MatchCases<T extends { tag: string }, R> = {
  [K in T['tag']]: (item: Extract<T, { tag: K }>) => R;
} & {
  default?: (item: never) => R;
};

// 通用match函数
function match<T extends { tag: string }, R>(
  input: T,
  cases: MatchCases<T, R>
): R {
  const handler = cases[input.tag as keyof typeof cases];
  if (handler) {
    return handler(input as Extract<T, { tag: typeof input.tag }>);
  }
  if (cases.default) {
    return cases.default(input as never);
  }
  throw new Error(`No handler found for tag: ${input.tag}`);
}

// 使用示例
const testInput: Third = { tag: 'one', value: 42 };
const result = match(testInput, {
  one: (item) => `Got number: ${item.value}`,
  two: (item) => `Got text: ${item.text}`
});

这种方式不用写重复的switch,逻辑更紧凑,而且同样能享受TypeScript的类型推断。

3. 类型层面的模式匹配:用条件类型处理类型转换

如果你的需求是类型层面的模式匹配(比如根据输入类型推导输出类型),可以用TypeScript的条件类型来实现,这在类型工具函数里很常用:

interface First { tag: 'one' }
interface Second { tag: 'two' }
type Third = First | Second

// 根据tag匹配对应的类型
type MatchResult<T> = 
  T extends { tag: 'one' } ? number :
  T extends { tag: 'two' } ? string :
  never;

// 测试:TypeScript自动推导结果类型
type Result1 = MatchResult<First>; // number
type Result2 = MatchResult<Second>; // string

你可以把这种类型层面的匹配和运行时逻辑结合,让类型和代码更一致。

4. 第三方库:用ts-pattern实现接近原生的模式匹配

如果你的场景比较复杂(比如嵌套结构、数组模式、通配符匹配),推荐用专门的模式匹配库ts-pattern,它的语法接近Rust、Scala这类语言的原生模式匹配,功能强大且类型安全:

import { match, P } from 'ts-pattern';

// 支持嵌套结构匹配
interface NestedFirst { tag: 'one', data: { id: number } }
interface NestedSecond { tag: 'two', data: { name: string } }
type NestedThird = NestedFirst | NestedSecond;

const result = match(someNestedValue)
  // 匹配tag为'one'且data.id大于10的情况
  .with({ tag: 'one', data: { id: P.gt(10) } }, (item) => `Large ID: ${item.data.id}`)
  .with({ tag: 'two' }, (item) => `Name: ${item.data.name}`)
  // 穷尽检查,漏写case会报错
  .exhaustive();

这个库还支持数组解构、可选值匹配、通配符等高级特性,适合中大型项目使用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:42:04