TypeScript编译为JavaScript后为何与CommonJS require不兼容?
Why TypeScript Compiles
export default to exports.__esModule Instead of module.exports 这其实是TypeScript为了兼容ES模块与CommonJS模块互操作性而做的设计,下面给你详细拆解:
核心原因:ES模块 vs CommonJS模块的差异
ES模块(ESM)和CommonJS(CJS)的模块结构本质不同:
- 在ESM里,每个模块可以有一个
default导出,同时还能有多个命名导出; - 而在CommonJS里,模块只有一个导出入口——
module.exports对象,没有单独的"default"概念。
TypeScript为了让ESM的代码能在CommonJS环境下正常工作,同时也让CommonJS模块能被ESM正确导入,会给编译后的模块添加exports.__esModule = true标记,并将ESM的default导出挂载到exports.default属性上。这个标记是告诉模块加载器:"这是一个从ESM编译过来的模块",从而在导入时正确处理导出内容。
你的代码问题所在
你用纯CommonJS的require()去导入TS编译后的模块时,拿到的是一个包含default属性的对象,而不是直接的函数。所以直接调用greet(...)其实是在调用这个对象,自然无法达到预期效果。
解决方法
这里有几个可行的方案:
1. 在CommonJS文件中手动取default属性
修改你的test.js:
const greet = require("./greet").default; greet({ name: 'Smith', age: 21 });
2. 在TypeScript中使用CommonJS风格导出
如果你不需要兼容ESM,直接在greet.ts里用CommonJS的导出语法:
module.exports = ({ name, age }) => `Name: ${name}, Age: ${age}`;
这样编译后就会直接生成module.exports = ...,和你预期的一致。
3. 用TypeScript的export =语法
这是TypeScript专门为兼容CommonJS设计的导出方式,修改greet.ts:
export = ({ name, age }) => `Name: ${name}, Age: ${age}`;
编译后同样会生成module.exports = ...的代码,同时也能被ESM的import语法正确导入(前提是你的tsconfig开启了allowSyntheticDefaultImports)。
内容的提问来源于stack exchange,提问作者李鸿章
相关产品推荐
相关产品推荐

