ts-node运行TS脚本动态导入JSON文件报未知扩展名错误如何解决
问题根因
ERR_UNKNOWN_FILE_EXTENSION .json报错来自三个核心问题:
- 动态导入代码存在语法错误:导入断言的配置对象未正确闭合,原代码中
{assert: { type: "json" }缺少结尾的},语法本身无法正常解析。 - 开启
ts-node的ESM模式后,模块加载遵循Node.js原生ESM规则,原生ESM默认不支持直接加载JSON文件。已配置的resolveJsonModule仅为TypeScript编译层面的类型支持,不会为Node运行时添加JSON加载能力,无法解决运行时的扩展名识别错误。 - ESM模式下Node.js与ts-node不会自动补全导入文件的
.ts后缀,和CommonJS模式的解析逻辑存在差异,才会出现必须手动标注.ts后缀才能正常导入的问题。
解决方案
根据是否需要保留ESM特性二选一即可:
方案1:保留ESM模式,补全JSON加载配置
- 首先修复动态导入的语法错误,注意ESM下动态导入的JSON内容默认挂载在模块的
default属性上,直接拿整个导入结果会拿到模块对象而非JSON内容,正确写法如下:
const serAcc = (await import(GOOGLE_APPLICATION_CREDENTIALS, { assert: { type: "json" } })).default as ServiceAccount;
- 修改
tsconfig.json中的ts-node配置,开启Node风格的路径解析,解决必须手动加.ts后缀的问题:
{ "ts-node": { "esm": true, "experimentalSpecifierResolution": "node" } }
- 运行脚本时添加Node原生JSON模块支持的flag,命令改为:
npx ts-node --esm --experimental-json-modules ./utility/storageScripts/uploadFile.ts
Windows环境如果直接执行上述命令报错,可先安装cross-env跨平台设置环境变量后执行;Node.js 18+版本已稳定支持ESM下的JSON导入,不需要额外加启动flag。
方案2:切换回CommonJS模式(无实验性依赖,更稳定)
如果不需要使用ESM专属特性,直接切回CommonJS模式是成本最低、最稳定的方案:
- 修改
tsconfig.json配置:- 将
compilerOptions.module改为CommonJS - 将
ts-node.esm设为false
- 将
- 配置完成后可直接用两种方式导入JSON,不需要额外加任何启动参数:
- 静态导入(路径为固定字符串时推荐):
import serAcc from "/path/to/service-account.json";
- 动态导入(路径存在变量时推荐):
const serAcc = require(GOOGLE_APPLICATION_CREDENTIALS) as ServiceAccount;
该模式下会自动补全.ts导入后缀,不需要手动添加扩展名,也不需要加@ts-ignore忽略类型报错。
注意事项
assert: { type: "json" }是ESM专属语法,CommonJS模式下不要添加,否则会触发语法错误。- 动态导入传入变量路径时,TypeScript无法自动推导导入内容的类型,需要手动添加类型断言匹配实际类型。
- 不要依赖
@ts-ignore绕过导入报错,这类报错本质是模块解析配置不匹配,调整对应配置即可彻底解决。
内容的提问来源于stack exchange,提问作者Matthew Keller
相关产品推荐
相关产品推荐

