如何在 Javascript/TypeScript 中实现C++里对象宏(常量宏)/全局常量的效果
本文介绍一种在 TypeScript 项目中实现C++里对象宏(常量宏)效果的实用方法,兼顾类型提示、开发体验和产物优化。
步骤一:在 global.d.ts
中声明全局常量
首先,在 global.d.ts
文件中声明一个 const
类型的全局变量。例如:
typescript
declare const __IS_DEV__: boolean;
注意:由于
const
语义不可修改,理论上你无法在代码中为它赋值或实现它。但实际上可以通过后续步骤解决。
步骤二:运行时安全赋值
- 编写一个
macro.ts
文件
typescript
if (typeof __IS_DEV__ === 'undefined') {
Reflect.set(globalThis, '__IS_DEV__', true);
}
- 在入口文件(如
main.ts
)最顶部,添加如下代码:
typescript
import '<path>/macro.ts';
细节说明
-
安全判断
除了
typeof __IS_DEV__ === 'undefined'
这种写法,其它所有涉及__IS_DEV__
的用法都会被视为"使用",在严格模式下会导致运行时错误。- 例如,不能写
if (__IS_DEV__)
,必须写if (typeof __IS_DEV__ === 'undefined')
。
- 例如,不能写
-
开发与生产环境兼容
- 在测试或开发环境下,
__IS_DEV__
会被设置为true
。 - 打包时,用 rollup 的 replace 插件将
__IS_DEV__
替换为false
,配合terser插件净化掉所有相关内容- 意味着
if (__IS_DEV__)
将变成if (false)
,因其永假性而被terser插件优化掉 - 同样的,定义处会变成
if (typeof false === 'undefined')
,因永假性而被terser消除
- 意味着
- 在测试或开发环境下,
-
类型提示与全局可用性
declare
的作用是让全局都能用到__IS_DEV__
并获得类型提示,编写时不会报错。- 只需在入口文件最上方加上上述定义,运行时即可安全使用。
步骤三:rollup replace 插件配置
在 rollup.config.mjs
中配置 replace 插件(名为@rollup/plugin-replace):
js
replace({
preventAssignment: true,
... // 其他配置
__IS_DEV__: 'false', // 生产环境下替换为 false
}),
总结
- 通过类型声明、运行时安全赋值和构建时替换,实现了C++里对象宏(常量宏)效果。
- 开发/测试环境下变量可用,生产环境下相关代码自动优化消除。
- 兼顾类型安全、运行安全和产物精简。