TypeScript中import替代require触发类型检查异常的处理方案咨询
Hey, 我之前也遇到过一模一样的问题!本质是TypeScript对ES模块和CommonJS模块的导出解析逻辑不一样导致的,下面逐个解答你的问题:
问题根源先搞懂
你看到的Property 'get' does not exist错误,是因为你的./config模块用module.exports = config(CommonJS的默认导出)把convict实例抛出去,但用import * as config from "./config"导入时,TypeScript会把config当成整个模块的命名空间对象,而不是那个convict实例——真正的实例其实在config.default里,所以直接调config.get()当然找不到方法。
1. 正确的处理方式
分两种场景给你解决方案:
导入自定义的config模块
别用import * as,改用默认导入就行:import config from "./config";如果还是报错,去你的
tsconfig.json里加上这两个配置,让TypeScript更好兼容CommonJS模块:{ "compilerOptions": { "esModuleInterop": true, "allowSyntheticDefaultImports": true } }这俩配置会让TypeScript把CommonJS的
module.exports自动当成ES模块的default导出,完美匹配你的导入写法。导入convict这类第三方库
首先确保你装了对应的类型包,这是类型检查的基础:npm install @types/convict --save-dev然后试试默认导入:
import convict from "convict";如果还是有问题,就用类型断言兜底:
import * as convictModule from "convict"; const convict = convictModule.default as typeof convictModule.default;
2. 能不能对import做类型转换?
必须可以!TypeScript的**类型断言(Type Assertion)**就是干这个的。比如当导入的模块类型不符合预期时,你可以用as关键字强制校正类型:
import * as configModule from "./config"; // 先转成unknown避免类型冲突,再转成convict实例的类型 const config = configModule as unknown as ReturnType<typeof import("convict").default>;
不过还是那句话,类型断言是兜底方案,能通过调整导入方式和配置解决的就别用这个,不然容易隐藏真正的类型问题。
3. 是不是所有require都能换成import?
大部分场景都可以,但有几个例外:
- 动态加载模块:
require可以在代码任意位置调用,但ES模块的静态import只能放在模块顶部。如果要动态加载,得用import()函数(返回Promise):// 原来的require写法 if (process.env.NODE_ENV !== "production") { const debug = require("request-debug"); } // 换成动态import if (process.env.NODE_ENV !== "production") { import("request-debug").then(debugModule => { const debug = debugModule.default; debug(requestJs); }); } - 导入非对象导出的模块:少数库直接导出函数、字符串这类非对象类型(比如
module.exports = function() {}),这时候如果用import * as会拿到一个包含default属性的对象,得用默认导入或者配合esModuleInterop配置。 - 旧版TypeScript导入JSON:TS 2.9之前导入JSON只能用
require,之后只要在tsconfig.json里开resolveJsonModule: true,就能用import导入JSON文件了。
内容的提问来源于stack exchange,提问作者Brian Jenkins

