【问题标题】:Import * as pgPromise from 'pg-promise' in pg-promise example causes typescript error TS2349: This expression is not callableImport * as pgPromise from 'pg-promise' in pg-promise example 导致打字稿错误 TS2349: This expression is not callable
【发布时间】:2021-06-30 13:17:46
【问题描述】:

在我的程序中调整推荐的打字稿示例

import * as pgPromise from 'pg-promise' ;
const pg = pgPromise() ;

没用。第二行导致错误:

This expression is not callable. Type 'typeof pgPromise' has no call signatures.ts(2349)

谷歌搜索错误消息并没有返回似乎与模块导入相关的答案,因为它们都处理调用不可调用对象。但是,我需要另一种解释:我不知道为什么 import 语句会生成一个非函数对象,尽管作者的明显意图是返回一个函数,该函数将启用具有多个参数的底层模块的初始化。

分析模块源代码没有多大帮助,它是用javascript编写的,看起来不是很透明。

【问题讨论】:

  • Here 是一个简单的示例,但它看起来与您的代码相似。 Here你可以找到一个 TypeScript 演示。
  • 正如我在问题中所描述的那样,这正是不起作用的那个 - 它返回上述错误。你试过在真实环境中运行它吗?
  • 是的,我下载了演示,遍历文件夹TypeScript,安装@types/expressnpm i @types/express,并使用最新的TypeScript 版本进行编译。有用。没有错误。没有警告。
  • 快递???我说的是 pg-promise。我什么都不需要快递。
  • The way it is shown in the project 应该足够了。如果它不起作用,那么您的身边肯定有问题。该库没有详细介绍 TypeScript,因为它与 JavaScript 相同。

标签: typescript tsconfig pg-promise


【解决方案1】:

终于我自己找到了答案。

示例中有一个错误。原进口声明:

import * as pgPromise from 'pg-promise' ;

导致错误,如问题中所述。正确的语法是:

import pgPromise from 'pg-promise' ;

然后它按预期工作。

【讨论】:

  • 没有错误。那是您的 TypeScript 配置问题。您的项目设置为使用默认导入,即esModuleInterop。这就是为什么它强制默认导入。这是 TypeScript 基础知识,pg-promise 没有问题。
  • Vitaly,我认为你应该修正你的自我描述:I do a lot of support on StackOverflow, helping developers with the libraries that I developed on GitHub, and some new technologies. 我建议将其修改为I present myself on StackOverflow a lot, explaining developers that libraries I developed are perfect and flawless and tell them to learn hard and solve there problems themselves。两者中哪一个更能描述你在这里的展览,你觉得呢?
  • 顺便说一句,有句话叫“没有错误的问题,只有错误的答案”。还有一些值得思考的事情......
【解决方案2】:

这是一个与转译为 javascript 和 ES6 规范相关的问题,并非特定于 pg-promise

至少有两种可能的方法来解决这个问题:

  1. 使用不同的语法:
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';

将导入对象属性namecolourage,并将它们分配给当前命名空间中的对象P。但是,它不会从上面的示例中导入函数p(),因为它在p 中没有命名属性;

  1. 快速而肮脏的解决方案是修复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 导入依赖于特定 Typescript 转译器配置的原因似乎是导出的命名空间是一个函数,而不是一个对象,这在 esModuleInterop = true 时是不允许的。 pg-promise 文档没有提到任何特定的 typescript 配置依赖或要求。

遗憾的是,pg-promise 的作者决定将傲慢的 cmets 留在这里,而不是在答案中指出 typescript 问题。

【讨论】:

  • 有一条警告消息提示解决方案#1:src/read-adif.ts:3:1 import * as pgPromise from 'pg-promise' ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~ Type originates at this import. A namespace-style import cannot be called or constructed, and will cause a failure at runtime. Consider using a default import or import require here instead.
猜你喜欢
  • 2016-11-17
  • 2018-03-15
  • 1970-01-01
  • 1970-01-01
  • 2021-09-16
  • 2017-04-13
  • 2021-12-12
  • 2021-01-08
  • 1970-01-01
相关资源
最近更新 更多