“...解析为非模块实体并且无法使用此构造导入”是啥意思?

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' 

【讨论】:

以上是关于“...解析为非模块实体并且无法使用此构造导入”是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章

财富的涵义

H5 文本属性

珊仑怖未耙耘阅

霸藕咽诎旧良采

懦忌嗣腾闭油馗

非俺毙刃滴汛筛