You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

手动编译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格式的文件做双模式兼容即可,不需要一步到位。

具体修改步骤

直接按以下顺序调整即可:

  1. 修改编译脚本的输出后缀
    把原来写入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;
    
  2. 补全package.json配置
    不需要加"type": "module"字段,保持默认CommonJS模式即可,同时补全入口、类型、导出映射配置,既支持去掉/dist/的简洁导入路径,也兼容原有导入写法:
    {
      "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"
      }
    }
    
    配置完exports字段后,消费方可以直接写import { SomeAPI } from "my-lib/some-api"导入,不需要加/dist/前缀,TS、node、打包工具都会自动映射到dist目录下对应的js和类型文件。
  3. 兼容性验证
    调整完成后各场景表现如下:
    • 本地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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 21:36:24