无损升级旧式定义到现代类的关键是选用AST驱动工具并严格控边界。应选TS Modernizer、Rector、Clang-Tidy等支持完整AST解析的引擎,启用语义级规则如构造函数转类、原型方法转类方法,禁用无关格式化;升级前后须验证接口签名、返回值、instanceof行为一致性,并将检查集成至CI与Git Hook流程。

直接用工具链完成旧式定义到现代类的无损升级,关键不在写脚本,而在选对工具、设对规则、控住边界。这类转换本质是语义重构,不是字符串替换,必须依赖能理解代码结构的引擎。
选对底层引擎:AST驱动而非正则匹配
所有可靠升级都基于抽象语法树(AST)解析。比如 TypeScript 项目用 JS/TS Modernizer,PHP 项目用 Rector,C++ 项目用 Clang-Tidy + IWYU,Python 项目用 pyupgrade 或 LibCST。它们能识别 var Person = function() {} 是构造函数声明,也能区分 function Person() {} 和 class Person {} 的语义差异,避免把工具函数误转为类。
- 拒绝基于正则的“查找替换”脚本——它会把 var list = []; 里的 var 错当变量声明处理
- 确认工具支持目标语言的完整 AST 解析能力,例如 Rector 支持 PHP 5.3–8.5 全版本 AST,Modernizer 支持 ES5–ES2023 模块与类语法推断
- 检查是否内置“安全模式”:如 Rector 的 --dry-run、Modernizer 的 Diff View、pyupgrade 的 --diff 参数
配置精准规则:聚焦类化核心逻辑
以 JavaScript/TypeScript 为例,真正需要升级的不是语法糖,而是原型链继承、构造函数绑定、this 指向混乱等结构性问题。配置时应关闭泛泛而谈的“格式美化”,专注启用语义级规则:
- 启用 Convert constructor functions to classes(Modernizer 默认开启)
- 启用 Convert prototype assignments to class methods(如 Person.prototype.say = function() {} → class Person { say() {} })
- 禁用自动改 var 为 const 等无关项,避免干扰主目标
- 对含 new 调用但无 this 赋值的函数,标记为“疑似工具函数”,不强制转类
保留行为契约:验证无损的关键动作
所谓“无损”,是指对外暴露的接口签名、返回值类型、副作用行为完全不变。仅靠工具无法保证,需人工介入验证环节:
- 升级前,提取所有被改造类的公共方法名、参数个数、返回类型(可用 TypeScript 的 ts-morph 或 Python 的 ast.unparse 辅助生成契约快照)
- 升级后,运行原有测试用例;若无测试,至少执行 new ClassName() 和调用每个公开方法,确认不抛异常
- 特别检查 instanceof 行为是否一致——现代类的 instanceof 判定逻辑与旧构造函数不同,必要时在类中手动实现 [Symbol.hasInstance]
集成进日常流程:让升级变成一次提交
把治理变成自动化流水线的一环,而不是专项运动:
- 在 CI 中加入 rector --dry-run 或 modernizer --check 步骤,阻断未按规范升级的 PR
- 配置 Git Hook(如 pre-commit),对新增/修改的 .js/.ts 文件自动运行轻量级升级检查
- 将转换结果输出为标准 diff 格式,嵌入 PR 描述模板,便于 Code Review 快速定位变更意图

















