Import * as pgPromise from 'pg-promise' in pg-promise example causes typescript error TS2349: This expression is not callable
Import * as pgPromise from 'pg-promise' in pg-promise example causes typescript error TS2349: This expression is not callable
在我的程序中采用推荐的打字稿示例
import * as pgPromise from 'pg-promise' ;
const pg = pgPromise() ;
没用。第二行导致错误:
This expression is not callable. Type 'typeof pgPromise' has no call signatures.ts(2349)
谷歌搜索错误消息并没有 return 看起来与模块导入相关的答案,因为它们都处理调用不可调用的对象。但是,我需要一种不同的解释:我不知道为什么 import 语句会产生一个非函数对象,尽管作者的明显意图是 return 一个函数,该函数将启用底层模块的初始化参数数量。
分析模块源代码没有太大帮助,它是用javascript写的,看起来不是很透明。
最后我自己找到了答案。
示例中存在错误。原进口报关单:
import * as pgPromise from 'pg-promise' ;
导致错误,如问题中所述。正确的语法是:
import pgPromise from 'pg-promise' ;
然后它按预期工作。
这是一个与转译为 javascript 和 ES6 规范相关的问题,并非特定于 pg-promise
。
至少有两种可能的方法来解决这个问题:
- 使用不同的语法:
import pgPromise from 'pg-promise' ;
此行按原样导入默认导出对象(在本例中为函数)。它更短,并且在我看来比以下行更直观,在示例中使用并由模块作者推荐:
import * as pgPromise from 'pg-promise' ;
要求导入的对象是对象(因为 * 表示将其所有属性导入主命名空间),因此它确实导入所有导出的属性,但不导入函数,因为函数未分配给属性,就是对象本身。
为了更详细地解释差异,
这是一个“普通”对象:
// module "module-p.js"
let p = { name: 'John', colour: 'blue', age: 1263 }
export default p ;
这是一个具有属性的函数对象:
let p = (x) => { console.log(x); } ;
p.name = 'John';
p.colour = 'blue';
p.age = 1263;
export default p ;
后者,当由
导入时
import * as P from 'module-p';
将导入对象属性 name
、colour
和 age
并将它们分配给当前命名空间中的对象 P
。但是,它不会从上面的示例中导入函数 p()
,因为它在 p
;
中没有命名 属性
- 快速而肮脏的解决方案是修复
tsconfig.json
中的选项 esModuleInterop
:
"esModuleInterop": true
至
"esModuleInterop": false
更改选项将启用 javascript 模块 pg-promise
和其他以类似 javascript 风格编写的模块所需的轻松模块导入处理。
https://www.typescriptlang.org/tsconfig#esModuleInterop 说:
默认情况下(esModuleInterop false 或未设置)TypeScript 对待 CommonJS/AMD/UMD 模块类似于 ES6 模块。在这样做的过程中,有两部分特别被证明是有缺陷的假设:
命名空间导入,如 import * as moment from "moment" 与 const moment = require("moment")
默认导入,如 import moment from "moment" 与 const moment = require("moment").default
这种不匹配会导致以下两个问题:
ES6 模块规范声明命名空间导入 (import * as x) 只能是一个对象,TypeScript 将其视为与 = require("x" ) 然后 TypeScript 允许将导入视为函数并可调用。这违反了规范的建议。
虽然符合 ES6 模块规范,但大多数具有 CommonJS/AMD/UMD 模块的库并不像 TypeScript 的实现那样严格。
pg-promise
import 依赖于特定 Typescript 转换器配置的原因似乎是导出的命名空间是一个函数,而不是一个对象,这在 esModuleInterop = true
时是不允许的。 pg-promise 文档未提及任何特定的 typescript 配置依赖项或要求。
可悲的是,pg-promise 的作者决定在这里留下傲慢的评论,而不是在答案中指出打字稿问题。
在我的程序中采用推荐的打字稿示例
import * as pgPromise from 'pg-promise' ;
const pg = pgPromise() ;
没用。第二行导致错误:
This expression is not callable. Type 'typeof pgPromise' has no call signatures.ts(2349)
谷歌搜索错误消息并没有 return 看起来与模块导入相关的答案,因为它们都处理调用不可调用的对象。但是,我需要一种不同的解释:我不知道为什么 import 语句会产生一个非函数对象,尽管作者的明显意图是 return 一个函数,该函数将启用底层模块的初始化参数数量。
分析模块源代码没有太大帮助,它是用javascript写的,看起来不是很透明。
最后我自己找到了答案。
示例中存在错误。原进口报关单:
import * as pgPromise from 'pg-promise' ;
导致错误,如问题中所述。正确的语法是:
import pgPromise from 'pg-promise' ;
然后它按预期工作。
这是一个与转译为 javascript 和 ES6 规范相关的问题,并非特定于 pg-promise
。
至少有两种可能的方法来解决这个问题:
- 使用不同的语法:
import pgPromise from 'pg-promise' ;
此行按原样导入默认导出对象(在本例中为函数)。它更短,并且在我看来比以下行更直观,在示例中使用并由模块作者推荐:
import * as pgPromise from 'pg-promise' ;
要求导入的对象是对象(因为 * 表示将其所有属性导入主命名空间),因此它确实导入所有导出的属性,但不导入函数,因为函数未分配给属性,就是对象本身。
为了更详细地解释差异,
这是一个“普通”对象:
// module "module-p.js"
let p = { name: 'John', colour: 'blue', age: 1263 }
export default p ;
这是一个具有属性的函数对象:
let p = (x) => { console.log(x); } ;
p.name = 'John';
p.colour = 'blue';
p.age = 1263;
export default p ;
后者,当由
导入时import * as P from 'module-p';
将导入对象属性 name
、colour
和 age
并将它们分配给当前命名空间中的对象 P
。但是,它不会从上面的示例中导入函数 p()
,因为它在 p
;
- 快速而肮脏的解决方案是修复
tsconfig.json
中的选项esModuleInterop
:
"esModuleInterop": true
至
"esModuleInterop": false
更改选项将启用 javascript 模块 pg-promise
和其他以类似 javascript 风格编写的模块所需的轻松模块导入处理。
https://www.typescriptlang.org/tsconfig#esModuleInterop 说:
默认情况下(esModuleInterop false 或未设置)TypeScript 对待 CommonJS/AMD/UMD 模块类似于 ES6 模块。在这样做的过程中,有两部分特别被证明是有缺陷的假设:
命名空间导入,如 import * as moment from "moment" 与 const moment = require("moment")
默认导入,如 import moment from "moment" 与 const moment = require("moment").default
这种不匹配会导致以下两个问题:
ES6 模块规范声明命名空间导入 (import * as x) 只能是一个对象,TypeScript 将其视为与 = require("x" ) 然后 TypeScript 允许将导入视为函数并可调用。这违反了规范的建议。
虽然符合 ES6 模块规范,但大多数具有 CommonJS/AMD/UMD 模块的库并不像 TypeScript 的实现那样严格。
pg-promise
import 依赖于特定 Typescript 转换器配置的原因似乎是导出的命名空间是一个函数,而不是一个对象,这在 esModuleInterop = true
时是不允许的。 pg-promise 文档未提及任何特定的 typescript 配置依赖项或要求。
可悲的是,pg-promise 的作者决定在这里留下傲慢的评论,而不是在答案中指出打字稿问题。