ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ts-jest 与 Babel7 的 TypeScript 方案对比:@babel/preset-typescript 的六大能力边界与 ts-jest 的完整替代

ts-jest 与 Babel7 的 TypeScript 方案对比:@babel/preset-typescript 的六大能力边界与 ts-jest 的完整替代 测试开发工具【免费下载链接】ts-jestA Jest transformer with source map support that lets you use Jest to test projects written in TypeScript.项目地址https://gitcode.com/gh_mirrors/ts/ts-jest点击查看免费下载Babel 7 于 2018 年 9 月发布并带来了专为 TypeScript 设计的预设babel/preset-typescript让 Babel 用户只需在配置中追加一个预设即可尝试 TypeScript。本文以 ts-jest 官方文档 Babel7 or TypeScript 为核心脉络系统梳理babel/preset-typescript与 TypeScript 原生编译器即 ts-jest 所采用的方案在能力上的本质差异类型检查、namespace、const enum、声明合并、legacyimport/export语法以及 JSX 下的尖括号类型断言。读完本文你将清楚判断自己的测试项目该选哪条路线并理解 ts-jest 在项目级编译语义上的底层原理。背景Babel7 与babel/preset-typescript的出现在 Babel 7 发布之前想要在 Babel 项目中体验 TypeScript通常需要引入额外的工具链。Babel7 通过官方预设babel/preset-typescript改变了这一局面——用户无需离开 Babel 生态只要在 Babel 配置中加入该预设就能对.ts/.tsx文件进行转译。它的设计目标是让 Babel 用户以最小的迁移成本尝试 TypeScript。但官方文档明确指出babel/preset-typescript是一个出色的预设使用它之前你必须了解它的能力边界Limitations。以下内容在 TypeScript 编译器以及基于 TypeScript 编译器的 ts-jest中可以正常工作但在 Babel7 babel/preset-typescript下却无法实现。这些差异本质上源于两条技术路线的底层定位不同Babel把每个文件当作孤立模块isolated module逐个转译只做语法层面的转换不做任何类型层面的检查或语义分析TypeScriptts-jest 所采用把文件纳入一个项目project的编译范围在项目上下文中做类型检查、符号解析与代码生成。限制一不做类型检查No type-checking这是 TypeScript 对比 Babel 的最大PRO优势开箱即用out of the box的类型检查能力。在测试场景下这个差异会直接影响开发体验。使用 ts-jest 时文件在被编译和运行的同时会执行类型检查也就是说你获得的是更流畅的TDD 体验——写错的类型会在测试运行时立即暴露而不是等构建阶段才被发现。例如下面这行代码TypeScript 会直接抛出类型错误而 Babel 会安静地把它转译过去const str: string 42Type number is not assignable to type string.从实现层面看这一差异对应着 ts-jest 的编译流水线设计。ts-jest 的 Jest 处理流程见 processing.md显示文件经过 transform 时ts-jest 会调用 TypeScript 编译器 API 对源码进行完整编译而不是像 Babel 那样只做语法转译。Babel 转译时没有项目的概念no notion of project而 TypeScript 明确地把文件视为项目的一部分在项目范围内编译。适用场景提示如果你的团队重视类型安全、希望在测试运行时同步获得类型反馈ts-jest 是更合适的选择如果你追求极致的转译速度、且类型检查由独立的 CI 步骤承担那么babel/preset-typescript的不做类型检查特性反而可能成为优势。限制二不支持namespacebabel/preset-typescript无法处理 TypeScript 的namespace语法namespace app { export const VERSION 1.0.0 export class App { /* ... */ } }namespace是 TypeScript 中组织代码的一种方式它会在编译期生成相应的运行时对象。由于 Babel 按文件孤立转译、缺乏跨文件的全局符号信息无法正确生成namespace的运行时语义因此该语法在 Babel 预设下不可用。而 ts-jest 使用 TypeScript 编译器namespace是完整的受支持特性。限制三不支持const enumconst enum常量枚举同样无法通过babel/preset-typescript转译const enum Directions { Up, Down, Left, Right, }const enum的特殊之处在于它在编译期会被内联为字面量值而不是生成运行时枚举对象因此它依赖 TypeScript 编译器对成员值的静态求值能力。Babel 的孤立模块转译无法完成这种跨文件的内联优化自然不支持该语法。这一点在 ts-jest 仓库中有完整的端到端验证。在 e2e/const-enum 目录下测试同时覆盖了两种使用形态编译器模式compilerts-jest 使用完整 TypeScript 编译器源码 src/bar-constant.ts 与声明文件 src/foo-constant.d.ts 中直接声明并导出const enum测试tests/const-enum.spec.ts 正常运行并断言成员值转译器模式transpiler / isolatedModulestsconfig-cjs-transpiler.spec.json 中开启isolatedModules: truets-jest 退化为按文件孤立转译——这正是文档所警告的会失去const enum等特性的场景。四个配置compiler-cjs、compiler-esm、transpiler-cjs、transpiler-esm由 e2e/tests/const-enum.test.ts 统一驱动逐一验证其运行结果。这组测试从侧面印证了官方文档的判断const enum是项目级编译的产物孤立转译模式下无法保证正确性。补充说明如果项目既想享受 Babel 类孤立转译的速度又需要const enumTypeScript 编译器提供了preserveConstEnums编译选项保留const enum的运行时声明而非仅内联。该选项在 ts-jest 的编译器选项类型 src/raw-compiler-options.ts 中有明确注释Disable erasingconst enumdeclarations in generated code可作参考。限制四不支持声明合并No declaration mergingBabel 预设下你无法使用 TypeScript 的声明合并declaration merging特性。声明合并允许同名声明如enum、namespace、接口等在类型系统中合并扩展例如在enum或namespace上追加成员。这种特性要求编译器在整个项目范围内汇总多个声明文件的信息而 Babel 的单文件孤立转译模型天然不具备该能力因此合并相关语法会被直接拒绝。ts-jest 走的是完整 TypeScript 编译链路项目级语义分析由 TypeScript 编译器完成声明合并在 ts-jest 中属于常规受支持能力。限制五不支持 legacyimport/export语法以下 TypeScript 早期的模块导入导出语法babel/preset-typescript同样不支持import lib require(lib) // ... export myVarimport lib require(lib)TypeScript 的导入赋值import assignment语法用于以 CommonJS 风格导入模块export myVar导出赋值语法用于把整个模块导出为单个值常用于 CommonJS 模块的类型声明。这两者都带有明确的 CommonJS 运行时语义Babel 预设无法还原其行为而 TypeScript 编译器可以按配置的模块系统module正确生成对应代码。ts-jest 的编译器选项类型 src/raw-compiler-options.ts 中列出了module的完整取值集合CommonJS、AMD、System、UMD、ES6/ES2015、ES2020、ESNext、Node16、NodeNext、Preserve等说明 ts-jest 会把模块语义交给 TypeScript 编译器按项目配置统一处理而不是简单剥离语法。限制六JSX 开启时无法使用尖括号类型断言No caret type-casting with JSX enabled当 JSX 功能开启时下面的尖括号caret类型断言写法在 Babel 预设下不可用const val stringinput原因在于string这种写法与 JSX 元素的标签语法存在语法歧义——编译器无法区分这是类型断言还是 JSX 元素。TypeScript 编译器在 JSX 模式下会正确处理这一歧义将stringinput解析为类型断言而 Babel 预设无法可靠区分因此直接不支持。实践建议在 JSX 项目中应统一改用as语法进行类型断言const val input as string这既兼容 Babel 转译也是 TypeScript 官方推荐的更明确的写法。两条路线的取舍与落地建议综合官方文档与仓库实现可以给出如下决策参考能力维度ts-jestTypeScript 编译器Babel7 babel/preset-typescript类型检查✅ 编译与运行同步进行适合 TDD❌ 不做任何类型检查namespace✅ 支持❌ 不支持const enum✅ 支持孤立转译模式下除外❌ 不支持声明合并✅ 支持❌ 不支持legacyimport/export✅ 支持❌ 不支持JSX 下尖括号断言✅ 支持❌ 不支持编译模型项目级project scope编译文件级孤立转译isolated module何时选择 ts-jest需要类型检查与测试运行一体化追求流畅的 TDD 反馈项目使用了namespace、const enum、声明合并、export 等 TypeScript 特有语法希望测试时的编译语义与tsc构建保持完全一致。何时考虑 Babel 预设已有成熟的 Babel 工具链希望复用现有的 Babel 插件如代码转换、Polyfill 策略类型检查已由 CI 或 IDE 独立承担测试阶段只求最快的转译速度。如果你倾向于 ts-jest 但希望在某些场景下换取转译速度可以关注 ts-jest 的isolatedModules相关配置详见 isolatedModules.md该模式让 ts-jest 按孤立模块逐个编译文件、跳过类型检查换取更快的测试运行速度但同时会失去类型检查和const enum等特性——这正是 Babel 路线能力边界的镜像。结语babel/preset-typescript的价值在于让 Babel 用户以极低门槛接触 TypeScript但它本质上是语法级的 TypeScript 支持类型检查、namespace、const enum、声明合并、legacy 导入导出与 JSX 下的尖括号断言这六类能力都依赖 TypeScript 的项目级编译语义因而成为 Babel 路线的天然边界。ts-jest 通过直接复用 TypeScript 编译器把完整的项目编译语义带入了 Jest 测试流程——这在 e2e/const-enum 的端到端测试和 processing.md 的处理流程文档中都有据可查。理解这两条路线的差异是选择测试工具链、排查Babel 能编译但测试报错类问题的关键起点。赞分享测试开发工具【免费下载链接】ts-jestA Jest transformer with source map support that lets you use Jest to test projects written in TypeScript.项目地址https://gitcode.com/gh_mirrors/ts/ts-jest点击查看免费下载相关推荐ts-jest 与 Babel7 之争babel/preset-typescript 的六项能力边界与 TypeScript 的完整实现ts jest 与 Babel7 之争 babel/preset typescript 的六项能力边界与 TypeScript 的完整实现 导读 本文基于测试开发工具ts-jest 与 Babel 7 对比babel/preset-typescript 的六大局限与 TypeScript 项目级编译的优势ts jest 与 Babel 7 对比babel/preset typescript 的六大局限与 TypeScript 项目级编译的优势 本文基于 ts测试开发工具ts-jest 与 Babel 7 babel/preset-typescript 选型指南六大特性差异与源码级解析ts jest 与 Babel 7 babel/preset typescript 选型指南六大特性差异与源码级解析 导读 Babel 7 于 201测试开发工具上一篇MobX 与 React 集成实战observer 组件、局部可观察状态与渲染追踪机制下一篇OLMo知识图谱构建从文本中抽取实体关系创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表