基于TypeScript泛型参数的日志函数编译优化:移除无效调用
问题:编译时移除无效日志函数调用
现有一段JavaScript代码,通过键值对控制日志是否输出:
const LoggedKeys = { logged: true, ignored: false, } function log(key, msg) { if(LoggedKeys[key]) console.log(msg); } log('logged', "This should be logged") log('ignored', "That should not do anything")
需求是将其改写为TypeScript版本,让对应值为false的键的log函数调用在编译时被移除,或生成空函数调用,以此避免大量无效调用带来的性能损耗。期望的使用方式大致如下:
interface LoggedKeys { logged: true, ignored: false, } type MyLogFunction<T extends keyof LoggedKeys> = LoggedKeys[T] extends true? (msg) => void: never // 使用示例 log<"logged">("That would generate proper log function") log<"ignored">("That would be erased during compilation or generate fake empty function during compilation")
解决方案
可以通过TypeScript字面量类型收窄、条件类型,结合构建工具的Tree-shaking能力实现需求,具体步骤如下:
1. 精确约束日志配置类型
用as const断言锁定日志配置的字面量值,让TypeScript能精准识别启用/禁用的日志键:
const LogConfig = { logged: true, ignored: false, } as const; type LogKey = keyof typeof LogConfig; // 筛选仅启用的日志键 type EnabledLogKey = { [K in LogKey]: typeof LogConfig[K] extends true ? K : never; }[LogKey];
2. 编写带类型校验的日志函数
通过函数重载区分启用/禁用键的调用逻辑,启用键正常输出日志,禁用键执行空逻辑:
// 重载:启用键的有效调用 function log(key: EnabledLogKey, msg: string): void; // 重载:禁用键的空调用 function log(key: Exclude<LogKey, EnabledLogKey>, msg: string): void; function log(key: LogKey, msg: string) { LogConfig[key] && console.log(msg); }
3. 用Tree-shaking彻底移除无效调用
上述代码编译后,禁用键的log调用会保留空执行逻辑。若要彻底清除这些调用,需配合构建工具的Tree-shaking:
- 确保
tsconfig.json中module设为ESNext/ES2020等ES模块格式; - 生产模式构建(如Webpack的
mode: "production")时,Tree-shaking会自动移除无副作用的空调用。
泛型风格实现(匹配你的期望示例)
如果想用泛型指定键的方式调用,可采用以下写法:
type LogFn<T extends LogKey> = typeof LogConfig[T] extends true ? (msg: string) => void : () => void; function log<T extends LogKey>(key: T): LogFn<T> { return LogConfig[key] ? (msg: string) => console.log(msg) as LogFn<T> : (() => {}) as LogFn<T>; } // 使用示例 log("logged")("This will output to console"); log("ignored")("This call will be removed in production build");
这种方式下,禁用键对应的日志函数是空实现,生产构建时会被Tree-shaking完全移除,不会产生任何性能开销。
内容的提问来源于stack exchange,提问作者mmierzwa
相关产品推荐
相关产品推荐

