
本文详解如何正确配置 TypeScript 编译、导出与打包,确保生成的 dist 文件可被 React 等前端项目正常导入使用,避免 undefined 或 is not a function 等运行时错误。
本文详解如何正确配置 typescript 编译、导出与打包,确保生成的 `dist` 文件可被 react 等前端项目正常导入使用,避免 `undefined` 或 `is not a function` 等运行时错误。
在将 TypeScript 代码构建成可供前端直接消费的包时,仅启用 declaration: true 和 noEmit: false 是远远不够的——关键在于输出格式(module format)、入口文件声明和构建产物完整性。你遇到的 myObject is undefined 和 getKeys is not a function 错误,本质是 Webpack(或 Vite)在解析 import { myObject, getKeys } from "my-package" 时,未能从 dist 中找到有效的 ES 模块导出,通常源于以下核心问题:
✅ 正确的 tsconfig.json 配置(关键项)
{
"compilerOptions": {
"target": "ES2018",
"module": "ESNext", // 必须设为 ESNext(而非 CommonJS),以生成原生 ES 模块
"lib": ["ES2018", "DOM"],
"declaration": true, // 生成 .d.ts 类型声明文件
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist",
"rootDir": "./src",
"moduleResolution": "node",
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"noEmit": false, // 允许 emit 输出
"emitDeclarationOnly": false // 确保同时输出 .js 和 .d.ts
},
"include": ["src/**/*"],
"exclude": ["src/**/*.test.ts"]
}⚠️ 特别注意:"module": "ESNext" 是前端可导入的前提;若设为 "CommonJS",则 dist/index.js 将使用 module.exports = {},而现代打包器默认按 ESM 解析,导致命名导入失败。
✅ 确保 package.json 显式声明模块入口
{
"name": "my-package",
"version": "1.0.0",
"main": "./dist/index.js", // CommonJS 入口(兼容旧工具)
"module": "./dist/index.js", // ESM 入口(Webpack/Vite 优先读取)
"types": "./dist/index.d.ts", // 类型定义入口
"exports": {
".": {
"import": "./dist/index.js", // ESM 模块路径(推荐)
"require": "./dist/index.js" // CJS 路径(如需 Node.js 支持)
}
},
"files": ["dist"]
}? exports 字段比 main/module 更精准,能强制现代打包器使用 ESM,避免降级到 CommonJS 导致的导出不匹配。
✅ 构建命令与验证
运行构建:
立即学习“前端免费学习笔记(深入)”;
tsc --build # 或使用 npm script: "build": "tsc --build"
构建后检查 dist/index.js 内容是否为有效 ESM:
// ✅ 正确示例(ESM 格式)
export const myObject = { a: 1, b: 2 };
export function getKeys() {
return Object.keys(myObject);
}
export function getValues() {
return Object.values(myObject);
}❌ 若看到 exports.myObject = ... 或 Object.defineProperty(exports, ...),说明 module 配置错误,仍在输出 CommonJS。
✅ 在 React 前端中安全使用
// ✅ 正确导入(基于 ESM)
import { myObject, getKeys, getValues } from "my-package";
console.log(myObject); // {a: 1, b: 2}
console.log(getKeys()); // ["a", "b"]⚠️ 常见陷阱与修复建议
- 未指定 rootDir / outDir 导致输出混乱:确保 src/index.ts 是唯一入口,且 outDir 不与 src 重叠。
- 缺少 types 字段:VS Code 能识别是因为 .d.ts 存在,但运行时无影响;types 字段确保类型检查准确。
- 未清理旧构建产物:执行 rm -rf dist && tsc --build 避免缓存干扰。
- React 项目未启用 ESM 解析:Vite 默认支持;Create React App(CRA)v5+ 也支持 ESM,但若用旧版 CRA,请升级或改用 craco 配置。
✅ 进阶推荐:使用 Rollup 或 tsup(更健壮)
对于库开发,纯 tsc 仅做转译,不处理 Tree-shaking 或 polyfill。推荐轻量打包工具:
npm install -D tsup
tsup.config.ts:
export default {
entry: ["src/index.ts"],
format: ["esm"], // 强制输出 ES 模块
dts: true, // 自动生成类型声明
outDir: "dist",
};运行 npx tsup 即可获得开箱即用的 ESM 包。
总结:TypeScript 库要被前端正确消费,核心是 ESM 输出 + 正确 package.json 入口声明 + 清晰的构建产物结构。跳过任一环节都可能导致运行时导出失效。务必验证 dist/index.js 是否为原生 export 语法,并通过 npm link 或本地 file: 依赖在真实 React 项目中测试导入行为。


















