- 跨平台
- 前端
【免费下载链接】react-native-windows
A framework for building native Windows apps with React.
本篇技术指南以 react-native-windows 仓库中@rnw-scripts/ts-config包(及其 CHANGELOG.md 记录的演进史)为核心,系统讲解这套被仓库内 30 余个包共同继承的 TypeScript 基准配置:它由哪些编译选项组成、每个选项在 monorepo 场景下承担什么职责、各子包如何通过extends继承并按需覆盖,以及这份配置从 0.0.1 到 2.0.6 的治理路线。读完本文,你可以完整复刻这套"一份 tsconfig 管全仓库"的工程实践,并理解esModuleInterop、isolatedModules、moduleSuffixes等选项在 React Native Windows 多平台构建中的真实作用。
一、包定位:一个"以 tsconfig.json 为产物"的私有配置包
@rnw-scripts/ts-config位于 packages/@rnw-scripts/ts-config,整个包只有 4 个文件:tsconfig.json、package.json、CHANGELOG.json、CHANGELOG.md。它不包含任何业务代码,全部价值都浓缩在 tsconfig.json 这一份编译器配置里。
从 package.json 可以看到它的关键设计:
{ "name": "@rnw-scripts/ts-config", "version": "2.0.6", "private": true, "license": "MIT", "main": "tsconfig.json", "engines": { "node": ">= 22" } }三个值得注意的点:
"main": "tsconfig.json":这是整套机制的核心。TypeScript 的extends字段既支持相对路径,也支持解析 npm 包名——当extends指向一个包名时,编译器会读取该包的main字段定位实际配置。把main直接指向tsconfig.json,就实现了"包名即配置"的消费方式。"private": true:该包不对外发布,仅通过仓库根目录 package.json 中声明的 Yarn workspaces(packages/*、packages/@rnw-scripts/*、vnext等)在 monorepo 内部解析。"engines": { "node": ">= 22" }:与 CHANGELOG.md 中 2.0.6 版本"Upgrade to node22"的记录相互印证——Node 运行时版本要求是全仓库一致的硬约束。
二、核心资产:逐项解读 19 个编译选项
tsconfig.json 的完整内容如下:
{ "compilerOptions": { "target": "ES2021", "module": "commonjs", "jsx": "react", "sourceMap": true, "declaration": true, "strict": true, "preserveConstEnums": true, "moduleResolution": "node", "noUnusedLocals": true, "strictNullChecks": true, "noImplicitReturns": true, "skipLibCheck": true, "resolveJsonModule": true, "esModuleInterop": true, "isolatedModules": true, "inlineSources": true, "experimentalDecorators": true, "noEmitOnError": true, "forceConsistentCasingInFileNames": true } }这 19 个选项可以按职责分为四组,每一组都对应 monorepo 治理中的一个具体诉求:
2.1 目标与产物组(输出形态)
| 选项 | 值 | 说明 |
|---|---|---|
target | ES2021 | 编译产物面向 ES2021 语法级别。历史版本曾使用 ES2017(见 CHANGELOG 0.1.0 条目),随运行环境升级逐步提升 |
module | commonjs | 模块系统使用 CommonJS,与仓库内大量 Node 侧脚本(CLI、自动化、发布工具)的运行方式一致 |
jsx | react | 使用 React 经典 JSX 转换,适用于仓库中*.tsx的组件代码 |
sourceMap | true | 生成 sourcemap,便于调试与错误栈还原 |
declaration | true | 生成.d.ts声明文件,使各包之间可以按类型化 API 互相消费 |
inlineSources | true | 把源文件内容内联进 sourcemap,方便在无法访问源码文件的场景下调试 |
2.2 严格性组(代码质量闸门)
| 选项 | 值 | 说明 |
|---|---|---|
strict | true | 开启 TypeScript 全量严格模式,是所有子包"默认严格"的基准 |
strictNullChecks | true | 空值检查,杜绝null/undefined隐式穿透 |
noUnusedLocals | true | 未使用的局部变量直接报错,强制清理死代码 |
noImplicitReturns | true | 所有代码路径都必须显式返回,防止漏写return |
noEmitOnError | true | 编译报错时不产出任何文件,避免把坏产物带入构建流水线 |
需要说明的是,strictNullChecks虽然与strict冗余,但显式列出它反映了仓库对空值安全这一单项的强制态度——即便某个子包因历史包袱关闭了整体strict(见下文react-native-win32的例子),空值检查仍被单独保留是各包自行决定的,而基准层显式声明它可以让覆盖语义更清晰。
2.3 模块解析与互操作组(跨包协作基础)
| 选项 | 值 | 说明 |
|---|---|---|
moduleResolution | node | 按 Node 经典解析规则查找模块,兼容 npm/yarn 安装的依赖 |
esModuleInterop | true | 允许对 CommonJS 模块使用import x from '...'默认导入。这是 2.0.0 版本"Enable esModuleInterop Repo Wide"这一major 变更的直接成果,从 CHANGELOG 可知该选项是整仓统一开启的 |
resolveJsonModule | true | 允许直接importJSON 文件,仓库内大量package.json、app.json读取依赖此能力 |
isolatedModules | true | 保证每个文件可被独立转译(对 Babel、Metro 等非 tsc 转译器友好),约束const enum、类型导出等写法 |
2.4 生态兼容组(第三方代码与历史包袱)
| 选项 | 值 | 说明 |
|---|---|---|
preserveConstEnums | true | 保留const enum运行时对象,配合isolatedModules缓解单文件转译下的枚举问题 |
experimentalDecorators | true | 开启装饰器支持,供仓库中装饰器风格的模块/原生模块声明使用 |
skipLibCheck | true | 跳过.d.ts文件的类型检查,显著加快编译并容忍第三方声明的瑕疵 |
forceConsistentCasingInFileNames | true | 强制文件名大小写一致,规避 Windows 文件系统大小写不敏感带来的跨平台隐患 |
三、消费方式:extends继承与按需覆盖的两种典型用法
仓库内共有33 个包的tsconfig.json直接以"extends": "@rnw-scripts/ts-config"继承这套基准配置,若加上根目录下的 vnext/tsconfig.json 则为 34 份。典型消费方包括@react-native-windows/cli、codegen、automation、telemetry、perf-testing、react-native-windows-init、react-native-platform-override以及各@rnw-scripts/*工具包。
3.1 零覆盖直接继承
大多数工具类包只做最简继承,例如 packages/@react-native-windows/codegen/tsconfig.json:
{ "extends": "@rnw-scripts/ts-config", "include": ["src"], "exclude": ["node_modules"] }这类包完全接受基准配置的全部语义,只补充include/exclude划定编译范围,从而获得一致的严格度、输出形态与模块解析行为。
3.2 按需覆盖:保留基准、修正差异
更常见的是在继承基础上针对包的特殊性做最小覆盖。下面几个例子展示了"基准层 + 差异层"的叠加哲学:
(1)平台变体解析——vnext 根配置(vnext/tsconfig.json):
{ "extends": "@rnw-scripts/ts-config", "compilerOptions": { "baseUrl": ".", "outDir": ".", "rootDir": "src-win", "moduleSuffixes": [".windows", ".native", ""], "paths": { "react-native": ["."] } }, "include": ["src-win"], "exclude": ["node_modules"] }moduleSuffixes: [".windows", ".native", ""]是 React Native Windows 平台分发的关键机制:编译器按.windows.ts→.native.ts→ 默认后缀的顺序解析同名模块,让 Windows 专属实现与上游 React Native 共享同一套源码结构;paths把react-native重映射到本地实现,实现"本地 RN 覆盖层"的接缝。
(2)历史包袱放宽严格度——packages/@office-iss/react-native-win32/tsconfig.json 因"Not clean"显式关闭strict,packages/@office-iss/react-native-win32-tester/tsconfig.json 则放宽noImplicitAny;这类覆盖以注释标注原因,明确这是临时债务而非常态。
(3)关闭单文件转译约束——packages/@react-native-windows/automation-channel/tsconfig.json 以"isolatedModules": false覆盖基准,因为其 C++/IDL 混编的构建链路对单文件隔离没有需求。
(4)注入测试类型——packages/debug-test/tsconfig.json 追加"types": ["jest"],在保留全部基准选项的同时为测试代码注入 Jest 类型。
(5)RN 入口重映射——packages/@react-native-windows/tester/tsconfig.json 将react-native通过paths指向../../../vnext,使测试应用直接编译本地 vnext 源码而非发布包。
这套模式的收益是:任何全局性的严格度、模块系统或 Node 版本策略调整,只需修改 tsconfig.json 一处,全仓库同步生效;个别包的历史债务则以显式、带注释的覆盖方式隔离,不会反向污染基准。
四、与 ESLint 配置的配套协同
共享 TypeScript 配置并非孤立存在,它与同目录体系下的 packages/@rnw-scripts/eslint-config/eslintrc.js 形成"编译 + 静态检查"双闸门:
{ files: ['*.ts', '*.tsx'], excludedFiles: ['*.d.ts'], parser: '@typescript-eslint/parser', parserOptions: { project: './tsconfig.json', }, ... }TypeScript ESLint 解析器的project: './tsconfig.json'直接复用各包继承自@rnw-scripts/ts-config的解析上下文,因此 ESLint 的类型感知规则(如await-thenable、no-floating-promises、no-unnecessary-condition等,见 eslintrc.js)与 tsc 看到的类型信息完全一致。可以推断:共享 tsconfig 不仅统一了编译行为,也统一了 lint 的类型基础,两者共同保证全仓库代码质量口径一致。仓库根 package.json 固定typescript: 5.0.4版本并统一通过lage编排各包构建,进一步锁定了工具链版本。
五、版本演进史:CHANGELOG 记录的治理路线
CHANGELOG.md(由 beachball 自动生成,声明"不应手工修改")完整记录了这套配置从诞生到当前版本的每一次变更,与 CHANGELOG.json(含提交哈希与作者信息)互为印证。按时间线整理如下:
| 版本 | 时间 | 变更内容 | 类型 |
|---|---|---|---|
| 0.0.1 | 2020-07-01 | Share eslint and Typescript configs across packages;Migrate the local-cli to TypeScript | patch |
| 0.1.0 | 2020-07-11 | Target ES2017 | minor |
| 2.0.0 | 2021-06-03 | Enable esModuleInterop Repo Wide | major |
| 2.0.1 | 2021-09-08 | Set consistent node requirements on our packages | patch |
| 2.0.2 | 2022-02-09 | Bump minimum Node version to 14 | patch |
| 2.0.3 | 2022-12-13 | Standardize on the repository field in package.json | patch |
| 2.0.4 | 2023-04-25 | Update Node to 16 | patch |
| 2.0.5 | 2023-07-14 | integration 6/28(与上游 React Native 的集成同步) | patch |
| 2.0.6 | 2025-08-23 | Upgrade to node22 | patch |
这份时间线折射出一条清晰的工程化路线:
- 从"建仓"到"统一"(0.0.1):包创建的初衷就是把散落在各包的 ESLint/TypeScript 配置抽成共享资产,同时借机把 local-cli 迁移到 TypeScript——共享配置与 TS 化改造是同步推进的。
- 互操作规范化(2.0.0,唯一 major):全仓库开启
esModuleInterop属于破坏性变更,必须独立大版本发布以强制各包同步调整导入写法,这解释了为何 0.1.0 之后直接跳到 2.0.0。 - Node 版本纪律(2.0.1 → 2.0.2 → 2.0.4 → 2.0.6):Node 最低版本要求从"统一要求"到 14、16,直至当前的 22,每一步都以 patch 形式随共享配置下发——工具链版本约束与编译配置一同分发,避免各包各自为政。
- 元数据标准化(2.0.3):
repository字段统一,服务于发布与溯源。 - 与上游节奏对齐(2.0.5):定期随上游 React Native 集成(integration)同步更新,保持配置与上游工具链兼容。
值得注意的是,CHANGELOG.json 还记录了 CHANGELOG.md 中未单独展示的两次补充提交(2025-07-18 的 header 命名空间变更、1.1.0 的 tag 升级),说明 MD 版只保留对外可见的语义化条目,JSON 版则保留完整的审计轨迹。
六、实践要点与 FAQ
Q1:新增一个 TypeScript 子包,如何接入这套体系?三步即可:在package.json的devDependencies中声明"@rnw-scripts/ts-config": "2.0.6"(仓库内各包当前统一锁定该版本),然后在tsconfig.json中写入:
{ "extends": "@rnw-scripts/ts-config", "include": ["src"], "exclude": ["node_modules"] }最后根据包的特殊性按需覆盖(参考第三节的五个例子)。由于包是private的,它只通过 Yarn workspaces 在仓库内解析,无需任何发布步骤。
Q2:为什么把配置做成一个"包",而不是根目录放一份 tsconfig 让各包相对路径引用?包化之后extends使用包名而非相对路径,路径解析与包版本锁定都由包管理器负责;同时 CHANGELOG 机制让每一次配置变更都有版本记录、可追溯、可回滚,这是裸tsconfig相对引用做不到的。
Q3:如何查看某个子包继承后的"最终生效配置"?在子包目录执行npx tsc --showConfig即可展开继承链,看到@rnw-scripts/ts-config的 19 个选项与该包自身覆盖合并后的完整结果,用于排查覆盖冲突或意外继承。
Q4:基准配置改选项会影响哪些包?只要保持语义兼容(如仅升级 Node 版本),改动一处即可让全部 34 份配置(33 个包 + vnext/tsconfig.json)同步生效;若语义破坏(如 2.0.0 的esModuleInterop),则按 semver 发布 major 版本,配合 beachball 的 change 文件机制通知全仓库协同升级。
结语
@rnw-scripts/ts-config虽然只是一个没有业务代码的"配置文件包",却是 react-native-windows 这座大型 monorepo 工程化的缩影:用包化与版本化的方式治理共享编译配置,用extends+ 最小覆盖的哲学兼顾统一与灵活,用 CHANGELOG 记录每一次治理决策。理解它的结构与演进,不仅有助于在阅读本仓库源码时快速定位类型系统的行为来源,也能为其他多包仓库的 TypeScript 配置治理提供一份可直接复用的参考范式。
- 跨平台
- 前端
【免费下载链接】react-native-windows
A framework for building native Windows apps with React.
相关推荐
react-native-windows 中 @rnw-scripts/jest-e2e-config:Node 端 E2E 测试共享 Jest 配置的演进与实践
react native windows 中 @rnw scripts/jest e2e config:Node 端 E2E 测试共享 Jest 配置的演进与实
跨平台前端react-native-windows 的共享 ESLint 配置包 @rnw-scripts/eslint-config:演进历史与规则体系深度解析
react native windows 的共享 ESLint 配置包 @rnw scripts/eslint config:演进历史与规则体系深度解析 在 r
跨平台前端react-native-windows 开发环境 Metro 配置指南:深入解析 @rnw-scripts/metro-dev-config
react native windows 开发环境 Metro 配置指南:深入解析 @rnw scripts/metro dev config 在 react
跨平台前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考