如何在 Javascript/TypeScript 中实现C++里对象宏(常量宏)/全局常量的效果

72 阅读2分钟

如何在 Javascript/TypeScript 中实现C++里对象宏(常量宏)/全局常量的效果

TypeScript全局常量.png

本文介绍一种在 TypeScript 项目中实现C++里对象宏(常量宏)效果的实用方法,兼顾类型提示、开发体验和产物优化。

步骤一:在 global.d.ts 中声明全局常量

首先,在 global.d.ts 文件中声明一个 const 类型的全局变量。例如:

declare const __IS_DEV__: boolean;

注意:由于 const 语义不可修改,理论上你无法在代码中为它赋值或实现它。但实际上可以通过后续步骤解决。


步骤二:运行时安全赋值

  1. 编写一个macro.ts文件
if (typeof __IS_DEV__ === 'undefined') {
  Reflect.set(globalThis, '__IS_DEV__', true);
}
  1. 在入口文件(如 main.ts)最顶部,添加如下代码:
import '<path>/macro.ts';

细节说明

  1. 安全判断
    除了 typeof __IS_DEV__ === 'undefined' 这种写法,其它所有涉及 __IS_DEV__ 的用法都会被视为“使用”,在严格模式下会导致运行时错误。

    • 例如,不能写 if (__IS_DEV__),必须写 if (typeof __IS_DEV__ === 'undefined')
  2. 开发与生产环境兼容

    • 在测试或开发环境下,__IS_DEV__ 会被设置为 true
    • 打包时,用 rollup 的 replace 插件将 __IS_DEV__ 替换为 false,配合terser插件净化掉所有相关内容
      • 意味着 if (__IS_DEV__) 将变成 if (false),因其永假性而被terser插件优化掉
      • 同样的,定义处会变成if (typeof false === 'undefined'),因永假性而被terser消除
  3. 类型提示与全局可用性

    • declare 的作用是让全局都能用到 __IS_DEV__ 并获得类型提示,编写时不会报错。
    • 只需在入口文件最上方加上上述定义,运行时即可安全使用。

步骤三:rollup replace 插件配置

rollup.config.mjs 中配置 replace 插件(名为@rollup/plugin-replace):

replace({
  preventAssignment: true,
  ... // 其他配置
  __IS_DEV__: 'false', // 生产环境下替换为 false
}),

总结

  • 通过类型声明、运行时安全赋值和构建时替换,实现了C++里对象宏(常量宏)效果。
  • 开发/测试环境下变量可用,生产环境下相关代码自动优化消除。
  • 兼顾类型安全、运行安全和产物精简。