TypeScript设计包时,如何避免非真实常量被编译进消费代码?
首先要明确:TypeScript模块级的export const(非const enum)和C#的public const行为不同——TS的普通export const编译后是运行时可访问的导出值,不会被消费方编译时硬编码到代码里。真正会像C#const那样被烘焙的是TS的const enum,这才是你需要重点规避的场景。
针对包设计,以下是几种优选模式:
避免使用
const enum,改用普通enumconst enum会被TS编译器直接把值替换到所有使用的地方,后续你更新枚举值时,消费方必须重新编译才能拿到新值。普通enum编译后是一个可访问的对象,消费方运行时读取枚举成员,能直接获取更新后的值。
示例:// 不推荐:会被烘焙 export const enum Timeouts { TenMinutes = 600000 } // 推荐:运行时读取 export enum Timeouts { TenMinutes = 600000 }用
readonly静态成员或冻结对象导出配置值
如果你有类级别的配置项,用readonly修饰静态成员,确保无法被修改的同时,消费方运行时读取最新值:export class PackageConfig { public static readonly DEFAULT_TIMEOUT = 60000; public static readonly MAX_RETRIES = 3; }模块级的配置集合,可以用
Object.freeze冻结对象,防止外部修改,同时保证运行时读取属性:export const PackageConfig = Object.freeze({ DEFAULT_TIMEOUT: 60000, MAX_RETRIES: 3 });用函数返回动态/可变的“常量”
如果你的值可能随环境或运行时状态变化(比如读取环境变量),不要直接导出常量,而是导出一个获取值的函数,确保消费方每次都拿到最新的运行时值:export function getDefaultTimeout(): number { return parseInt(Deno.env.get("PACKAGE_DEFAULT_TIMEOUT") || "60000", 10); }
总结一下:如果是永远不会变更的真实常量(比如数学常数、固定业务枚举值),用export const或const enum都没问题;如果是可能后续调整的配置值,优先选择普通enum、readonly成员、冻结对象或函数返回值,这样消费方不需要重新编译就能获取到包更新后的新值。
内容的提问来源于stack exchange,提问作者Luke Puplett

