“...解析为非模块实体并且无法使用此构造导入”是啥意思?
Posted
技术标签:
【中文标题】“...解析为非模块实体并且无法使用此构造导入”是啥意思?【英文标题】:What does "... resolves to a non-module entity and cannot be imported using this construct" mean?“...解析为非模块实体并且无法使用此构造导入”是什么意思? 【发布时间】:2017-01-17 20:17:59 【问题描述】:我有一些 TypeScript 文件:
MyClass.ts
class MyClass
constructor()
export = MyClass;
MyFunc.ts
function fn() return 0;
export = fn;
MyConsumer.ts
import * as MC from './MyClass';
import * as fn from './MyFunc';
fn();
这在尝试使用 new
时给了我错误
模块“MyClass”解析为非模块实体,无法使用此构造导入。
当尝试拨打fn()
时
无法调用类型缺少调用签名的表达式。
什么给了?
【问题讨论】:
感谢分享答案。我建议删除javascript
作为主要标签并保留ecmascript-6
,因为这里的主要标签是typescript
。该问题错误地假设export =
(TS 功能)可能与import ... from
配对,而it should be paired with import =
。它基本上是 ES6 模块导入/导出 vs CJS/AMD。
【参考方案1】:
为什么它不起作用
import * as MC from './MyClass';
这是 ES6/ES2015 风格的 import
语法。其确切含义是“获取从./MyClass
加载的模块命名空间对象,并在本地将其用作MC
”。值得注意的是,“模块命名空间对象”只包含一个带有属性的普通对象。 ES6 模块对象不能作为函数或new
调用。
再说一遍:ES6 模块命名空间对象不能作为函数或new
调用。
你import
使用模块中的* as X
的东西被定义为只有属性。在降级的 CommonJS 中,这可能没有得到完全尊重,但 TypeScript 会告诉你标准定义的行为是什么。
什么有效?
你需要使用 CommonJS 风格的导入语法来使用这个模块:
import MC = require('./MyClass');
如果你控制这两个模块,你可以使用export default
来代替:
MyClass.ts
export default class MyClass
constructor()
MyConsumer.ts
import MC from './MyClass';
我为此感到难过;规则是愚蠢的。
使用 ES6 导入语法会很好,但现在我必须这样做import MC = require('./MyClass');
的事情?这是2013年!瘸!但悲伤是编程的正常部分。请跳至 Kübler-Ross 模型的第五阶段:接受。
TypeScript 在这里告诉你这是行不通的,因为它行不通。有一些技巧(将namespace
声明添加到MyClass
是一种流行的方式来假装它有效),它们可能今天在您的特定降级模块捆绑器(例如汇总)中工作,但这是虚幻。目前还没有任何 ES6 模块实现,但不会永远如此。
想象一下你未来的自己,试图在一个整洁的原生 ES6 模块实现上运行,并发现你已经通过尝试使用 ES6 语法来做一些 ES6 明确不做的事情,从而使自己面临重大失败 /em>。
我想利用我的非标准模块加载器
也许你有一个模块加载器,当不存在时“有用地”创建default
导出。我的意思是,人们制定标准是有原因的,但有时忽略标准很有趣,我们可以认为这是一件很酷的事情。
将 MyConsumer.ts 更改为:
import A from './a';
并指定allowSyntheticDefaultImports
命令行或tsconfig.json
选项。
请注意,allowSyntheticDefaultImports
根本不会改变代码的运行时行为。它只是一个标志,告诉 TypeScript 你的模块加载器在不存在时创建 default
导出。它不会神奇地让你的代码在 nodejs 中运行,而之前它没有。
【讨论】:
commonjs 样式不需要commonjs 目标吗?当您以 es6/es2015 为目标时,有没有办法让它工作? 你不能让它针对 ES6 工作因为它在 ES6 中不起作用... 我是否正确理解如果我的目标是 ES2015 模块,则无法引用具有export = MyClass
的 CommonJS 模块?我唯一的选择是将我的模块设置为 commonjs
并继续通过不使用现代 ES 让世界变得更糟?
在2.7 release notes 的--esModuleInterop
下,它说“我们强烈建议将其应用于新项目和现有项目”。在我看来,应该修改这个答案(以及链接到此处的DefinitelyTyped
中的FAQ entry/policy)以反映新的立场。
太时髦了。【参考方案2】:
TypeScript 2.7 通过发出新的辅助方法来引入支持: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#support-for-import-d-from-cjs-form-commonjs-modules-with---esmoduleinterop
所以在 tsconfig.json 中添加这两个设置:
// Enable support for importing CommonJS modules targeting es6 modules
"esModuleInterop": true,
// When using above interop will get missing default export error from type check since
// modules use "export =" instead of "export default", enable this to ignore errors.
"allowSyntheticDefaultImports": true
现在你可以使用:
import MyClass from './MyClass';
【讨论】:
我没有使用esModuleInterop
,而是使用了resolveJsonModule
以及您使用allowSyntheticDefaultImports
的其他建议,它对我有用。【参考方案3】:
在此处添加我的 2 美分,以防其他人遇到此问题。
我在不修改 tsconfig.json
的情况下解决问题的方法(这在某些项目中可能会出现问题),我只是禁用了 oneline 的规则。
import MC = require('./MyClass'); // tslint:disable-line
【讨论】:
【参考方案4】:尝试在我的项目中包含 npm debounce 包时出现此错误。
当我尝试上面接受的解决方案时,我遇到了一个异常:
以 ECMAScript 模块为目标时,不能使用导入分配。 考虑使用'import * as ns from "mod"'、'import a from "mod"'、 'import d from "mod"',或其他模块格式。
这最终奏效了:
import debounce from 'debounce'
【讨论】:
以上是关于“...解析为非模块实体并且无法使用此构造导入”是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章