JavaScript 实现类 C# Switch 表达式:从策略模式到 TypeScript 类型安全

作者:代码拾荒

时间:2026-10-26

浏览:531

本文探讨如何在 JavaScript 中实现类似 C# 的 switch 表达式。通过策略模式构建 when 函数,解决传统 switch 穿透问题,并进一步利用 TypeScript 强化类型安全与参数简化,最终提供 npm 包方案。

文章目录

正文

在 C 和 Java 等语言体系中,switch 语法是多分支处理的经典手段。然而,传统 switch 语句存在分支穿透特性,必须依赖 break 来强制中断逻辑,这常被视为该语法的主要隐患之一。此外,所有 case 分支共享同一作用域,也限制了代码的灵活性与安全性。

C# 8.0 引入了 switch 表达式,其语法丰富且支持模式匹配与解构等高级特性。尽管此处不展开讨论这些高级功能,但 switch 表达式对传统 switch 语句进行了关键改进:

  • 使用箭头 (=>) 明确标识 case 与处理逻辑的一对一关系,无需 break 语句,彻底消除穿透风险;
  • 作为表达式,它必须且能够返回值;

新的约束

  • switch 表达式要求逻辑详尽(必须覆盖所有可能路径,可通过弃元模式兜底),否则运行时可能抛出异常。

在 C# 8.0 发布的同年,Java 12 也发布了 switch 表达式预览版。Java 的实现较为简单,仅支持从 switch 语句到表达式的直接转换,且仅支持等值匹配。直到 2023 年 3 月 Java 20 发布,switch 表达式才开始支持模式匹配。相比之下,Kotlin 的 when 表达式起步更早。

JavaScript 在此方面似乎进展较慢,但在语言原生支持 switch 表达式之前,我们可以通过自行封装来实现类似功能。

核心思路借鉴策略模式。假设有一个列表,每个元素包含两个部分:第一个用于判断是否命中条件,第二个是执行函数以获取计算结果。通过遍历列表,一旦某个元素命中,便执行其携带的函数获取结果并中断循环返回。若列表最后一项必定命中,则该列表被视为“详尽”。

when 函数写法

那么,这个 when 函数可能如下实现(由于 switch 是关键字,故使用 when 作为函数名):

// JS
function when(value, ...cases) {
    for (const { is, run } of cases) {
        if (is(value)) {
            return run(value);
        }
    }
    throw new Error("非详尽");
}

此处假设每个情况 (case) 包含 is 方法用于判断命中条件,以及 run 方法保存命中后需执行的操作。

分算等级”测试

我们可以使用经典的“分数算等级”案例进行测试:

// JS
function calcGrade(score) {
    return when(
        score,
        { is: v => v >= 0 && v < 80, run: v => `不合格 (${v})` },
        { is: v => v >= 80 && v < 100, run: v => `合格 (${v})` },
        { is: v => v == 100, run: v => `满分 (${v})` },
        { is: _ => true, run: v => `无效 (${v})` },
    );
}
for (let i = 0; i < 50; i++) {
    const v = 70 + ~~(Math.random() * 35);
    console.log(calcGrade(v));
}

在 calcGrade 实现中,when 的 case 列表最后一项采用了“永真”断言,因此到达该项时必命中,逻辑上不会触发 Error。若非“详尽”列表,则可能触发 Error。

测试问题

然而,从测试代码中可发现两个问题:

  • is 断言以函数形式存在,无法直接进行值匹配;
  • 从调用形式看,score 与后续 case 元素同级,形式区分不明显;
  • 每次均需编写 is 和 run,条件增多时编写繁琐。

继续改进 ——

// JS
function when(value) {
    // when 的参数先给 switch 的值
    // 返回一个函数来处理分支匹配 ②
    return function (...cases) {
        for (const [is, run] of cases) {
//                 ^^^^^^^^^ 从对象改为元组(数组)③
            if (value === is || (typeof is == "function" && is(value))) {
//                    ^^^^^^ 精确判断 ①
//                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 断言函数判断
                return  run(value);
//                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 可指定行为(函数)
            }
        }
        throw new Error("非详尽");
    };
}
function calcGrade(score) {
    return when(score)(
//         ^^^^^^^^^^^ 这里返回的是匹配处理的函数
        [v => v >= 0 && v < 80, v => `不合格 (${v})`],
        [v => v >= 80 && v < 100, v => `合格 (${v})`],
        [100, () => "满分 (100)"],
//       ^^^ 可以指定匹配的值
//            ^^ 计算不需要参数,可以不声明
        [_ => true, v => `无效 (${v})`],
//       ^^^^^^^^^ 兜底的永真断言
    );
}

为何兜底断言必须使用函数?因为 true 值也可能对应某种预想分支。由于 when 通过语义而非语法实现,无法定义安全的兜底断言语法,使用断言函数相对更安全。

升级成 TypeScript

至此,我们已基本实现 switch 表达式 (when),现在将其升级为 TypeScript 版本。

// TypeScript
type CaseCondition<T> = T extends Function ? never : ((t: T) => boolean) | T
type Case<T, R> = [CaseCondition<T>, (t: T) => R];
function when<T>(value: T): <R>(...cases: Case<T, R>[]) => R {
    return function<R>(...cases: Case<T, R>[]): R {
        for (const [is, run] of cases) {
            if (value === is || (typeof is == "function" && is(value))) {
                return run(value);
            }
        }
        throw new Error("非详尽");
    };
}
function calcGrade(score: number) {
    return when(score)(
        [v => v >= 0 && v < 80, v => `不合格 (${v})`],
        [v => v >= 80 && v < 100, v => `合格 (${v})`],
        [100, () => "满分 (100)"],
        [_ => true, v => `无效 (${v})`],
    );
}

此代码可直接使用,但若通过 npm 安装可能更为便捷:

npm install @jamesfancy/when
// TypeScript
import { when } from "@jamesfancy/when";
function calcGrade(score: number) {
    return when(score)(
        [v => v >= 0 && v < 80, v => `不合格 (${v})`],
        [v => v >= 80 && v < 100, v => `合格 (${v})`],
        [100, () => "满分 (100)"],
        [_ => true, v => `无效 (${v})`],
    );
}

以上就是JS语法也可以有C# 的switch表达式的详细内容,更多关于JS语法C# switch表达式的资料请关注本站其它相关文章!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章