为什么在JavaScript中使用TypeScript类需要`.default`?

Tod*_*Tod 7 javascript typescript

我有一个TypeScript类,它是npm包的一部分。为了维护,我将该类分解为多个类,并通过继承建立了最终的导出类。我认为这与我的问题无关,但我认为最好公开这些信息。我这样定义类ChildClass.ts

export default ChildClass extends ParentClass{…}
Run Code Online (Sandbox Code Playgroud)

Tsc具有outDir“构建”。
package.json文件具有属性"main": "build/ChildClass.js"

同时使用npm linknpm pack和,我可以在TypeScript演示程序包中部署该程序包并使用它,而不会出现问题。但是,如果我尝试在JavaScript演示中使用该软件包,

const ChildClass = require('my-package')
const childClass = new ChildClass()
Run Code Online (Sandbox Code Playgroud)

我得到错误
Cannot use 'new' with an expression whose type lacks a call or construct signature.ts(2351)

如果我new通过添加.default如下语句来更改语句:

const childClass = new ChildClass.default()

有用。我通过查看已编译的Javascript来解决这个问题。不得不使用.default 我作为期望我的包的(假设)JavaScript使用者知道的不合理的事情。我还发现,如果我避免使用export default 而只是使用它,export那么该程序包将更可预测地工作,所以我就是这样做的。现在我可以使用

const {ChildClass} = require('my-package')
const childClass = new ChildClass()
Run Code Online (Sandbox Code Playgroud)

和类似的语法

export default ChildClass extends ParentClass{…}
Run Code Online (Sandbox Code Playgroud)

在打字稿中。

不过,我想知道这个神奇的.default属性是什么,为什么我需要它。

另外,我发现的所有其他有关此错误的参考似乎都与我所看到的不相关。我认为记录此文档可能会帮助遇到类似错误的其他人。

Sim*_*han 9

背景:

ECMAScript 语言规范指定导出的名称export default仅为"default". 所以你可以把它想象成一个名为"default".

将 ES6 模块编译为 CommonJS 只有一个事实上的标准,因为 ECMAScript 语言规范从未提及它。目前的转译器(TypeScript 和 Babel)只是将所有导出放到module.exports,默认导出不再特别。

只有当消费者也理解了上述“标准”(例如TypeScript、Babel 和Webpack)时,他们才会为你转换import ChildClass from 'my-package语句const ChildClass = require('my-package').default。当然,Node.js 是分别处理 CommonJS 和 ES6 模块的,并没有这样做。

(实际上它更复杂,因为 Babel 混合了import DefaultExport from 'some-package'import * as AllExports from 'some-package,现代模块消费者必须同时尝试两者)


解决方案:

TypeScript 有一种特殊的语法 export =来处理传统的 CommonJS 消费者(它不是在 JavaScript 中)。如果您更改export default class ChildClass...export = class ChildClass...,它应该会按您的预期工作。