手动编译TypeScript库适配React TS应用与Jest的最佳实践咨询
TS自定义构建库兼容React应用与Jest的标准实现方案
核心问题定位
你之前遇到的所有报错,本质都是输出文件格式、模块规范和消费端的预期不匹配导致的,几个典型错误点:
- 把
.ts后缀的文件作为运行时输出放在dist目录是核心错误。发布到npm供外部消费的库,运行时代码绝对不能用.ts后缀,node、Jest、前端打包工具默认都不会把.ts文件当做可直接执行的JS模块,这也是你之前反复报模块相关错误的根源。 - 盲目给package.json加
"type": "module"会直接打乱你本地基于CommonJS配置的ts-node构建链路,ESM和CommonJS的配置不需要全局二选一,完全可以做到构建脚本和库输出互不影响。 - 拆分运行时代码和.d.ts类型文件的思路是对的,但之前把运行时代码存成.ts后缀的操作,导致TS和JS模块解析逻辑完全混乱,才会出现“文件不是模块”“类型识别失败”的问题。
标准输出结构规则
面向TS+React+Jest技术栈消费的库,dist目录的输出只要遵守以下规则即可,不需要复杂的特殊适配:
- 所有运行时代码统一使用
.js后缀,优先输出CommonJS规范(使用module.exports/require语法),该格式对node、Jest、所有主流前端打包工具100%兼容,不需要消费方额外做转译配置。 - 所有类型声明文件和对应的.js文件同名同目录存放,使用
.d.ts后缀,类型文件里用标准ESM的export/import语法写导出即可,TS会自动完成同目录同名js和d.ts文件的映射,不需要额外配置路径映射规则。 - dist目录禁止存放任何带TS类型语法的运行时代码文件,保证所有.js文件是纯可直接执行的ES6标准代码,不需要二次编译就能跑。
- 不需要单独建平行的types目录存放类型文件,同目录放置是TS官方推荐的兼容性最高的方案,比单独目录配置更少,不会出现类型映射丢失的问题。
- 不需要强制配置
"type": "module",CommonJS输出足够覆盖当前的消费场景,后续如果需要支持ESM消费,再额外输出一份ESM格式的文件做双模式兼容即可,不需要一步到位。
具体修改步骤
直接按以下顺序调整即可:
- 修改编译脚本的输出后缀
把原来写入dist的.ts运行时代码全部改为.js后缀,导出逻辑保持CommonJS写法不变,示例:
对应的类型声明文件保持// dist/example.js module.exports.defaultExample = { title: 'whatever', name: 'Whatever' };dist/example.d.ts命名,你当前写的d.ts内容是正确的,不需要修改:// dist/example.d.ts export interface Document { title: string; name: string; size?: number; mimeType?: string; data?: string; } export declare const defaultExample: Document; - 补全package.json配置
不需要加"type": "module"字段,保持默认CommonJS模式即可,同时补全入口、类型、导出映射配置,既支持去掉/dist/的简洁导入路径,也兼容原有导入写法:
配置完exports字段后,消费方可以直接写{ "version": "1.0.2", "main": "./dist/index.js", "types": "./dist/index.d.ts", "exports": { "./some-api": { "types": "./dist/some-api.d.ts", "default": "./dist/some-api.js" }, "./*": { "types": "./dist/*.d.ts", "default": "./dist/*.js" } }, "files": [ "./dist" ], "scripts": { "compile:openapi": "ts-node scripts/compileOpenapi.ts" }, "engines": { "node": "^16.14.0" } }import { SomeAPI } from "my-lib/some-api"导入,不需要加/dist/前缀,TS、node、打包工具都会自动映射到dist目录下对应的js和类型文件。 - 兼容性验证
调整完成后各场景表现如下:- 本地ts-node构建脚本不受任何影响,因为没有修改全局type配置,依然运行在CommonJS环境下,不会出现.ts后缀识别错误的问题。
- React应用导入时,打包工具直接加载纯JS格式的文件,不需要转译node_modules下的TS代码,构建速度更快。
- Jest运行测试时直接加载CommonJS规范的JS文件,不会再出现“cannot use import statement outside a module”的报错,不需要额外配置transformIgnorePatterns规则。
- TS会自动通过exports配置找到对应的d.ts文件,类型提示、类型校验完全正常,不会出现“导入文件不是模块”的警告。
补充说明
不要参考lodash这类历史悠久的通用库的实现,这类库为了兼容十几年前的各种老旧环境、模块规范加了大量特殊适配逻辑,对于面向现代TS+React技术栈的库来说完全是冗余的,按上述标准结构输出即可满足所有常规消费场景。
合格的npm库发布时,运行时代码必须是可直接在node环境执行的纯JS代码,要求消费方修改转译配置适配库的未编译源码属于反模式,应该避免。
内容的提问来源于stack exchange,提问作者Sasha
相关产品推荐
相关产品推荐

