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

TypeScript中export =与import = require()语法含义及使用问题

报错直接原因

你代码里抛'CJSModule.ts' is not a module.ts(2306)的核心原因很简单:TS不会把仅手动写了module.exports = xxx、没有使用TS/ESM标准导出语法的文件识别为TS模块。你把文件里注释掉的export = helloCJS放开,删掉手动写的module.exports = helloCJS那行,报错会立即消失。
注意:export =本身就是TS提供的语法,当你编译目标是CommonJS时,TS会自动把这句语法编译成module.exports = helloCJS,完全不需要你手动写原生CJS的导出语句。

语法作用与使用场景

你对这套语法的适配方向有误解:它不是用来兼容你手动写的原生CJS导出语句的,而是TS为了覆盖CommonJS/AMD模块的导出逻辑提供的类型安全的模块语法,核心使用场景有两个:

  • 当你写TS代码需要编译输出为CommonJS/AMD格式,且需要把整个模块导出为单个函数、类或值(而不是在exports上挂多个属性)时,用export =导出,搭配import xxx = require()导入,TS可以完整推导类型,编译后的代码也完全符合CJS/AMD的模块规范。正确写法示例:
// CJSmodule.ts
function helloCJS(): void {
  console.log("CJSModule");
}
// 编译到CommonJS时自动生成 module.exports = helloCJS
export = helloCJS;
// index.ts
// TS会自动推导helloCJSModule1的类型为() => void,无报错
import helloCJSModule1 = require("./CJSModule");
helloCJSModule1();
  • 给传统纯JS编写的CommonJS存量模块编写类型声明文件(.d.ts)时,必须用这套语法才能准确匹配原模块的导出形状。比如一个老CJS包的导出是直接覆盖整个module.exports为一个函数,你写声明时就必须用export =对应,否则TS推导出的导入类型会和实际运行值不符。
为什么ES模块普及后还保留这套语法

核心原因是ES模块和CommonJS的导出逻辑存在不可调和的不兼容,ES标准的export default无法完全替代export =的能力:

  • ES模块的默认导出编译到CommonJS时,只会在exports对象上挂载一个default属性,也就是会编译成exports.default = xxx,不会直接覆盖整个module.exports对象。这和传统CJS模块直接替换整个exports对象的行为完全不一致。
  • 举个最常见的场景:你维护一个需要兼容低版本Node.js(无原生ESM支持)的工具库,所有用户都是用const lib = require('你的包')的方式引入。如果你用ES默认导出,用户引入后拿到的是{ default: 实际导出值 }的对象,必须写lib.default()才能调用,完全不符合CJS生态的使用习惯。这种场景下你只能用export =语法,才能编译出符合用户预期的CJS模块代码。
  • 除此之外,npm上存在海量的CommonJS格式的存量包,这些包的类型定义必须依赖export =语法才能准确描述,不可能因为ES标准语法的存在就抛弃整个存量生态。

内容的提问来源于stack exchange,提问作者JackyChen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 16:21:34