【问题标题】:New es6 syntax for importing commonjs / amd modules i.e. `import foo = require('foo')`用于导入 commonjs / amd 模块的新 es6 语法,即 `import foo = require('foo')`
【发布时间】:2023-03-11 09:50:02
【问题描述】:

以前我可以这样做:

import foo = require('foo');

但是现在 TypeScript (1.5) 支持 es6 模块语法,在 ES6 模块语法中实现相同的正确方法是什么。

【问题讨论】:

标签: javascript typescript ecmascript-6


【解决方案1】:

另一种选择是使用 CommonJS 语法导入它:

const foo = require("foo");

TypeScript 和 Babel 都同意如何处理这个问题。另外,如果你编译到 ES5 或更少,那么这与它的最终形式不会相差太远。

【讨论】:

    【解决方案2】:

    全部导入,

    const foo = require("foo");
    

    如果它是一个文件,这将从包“foo”中导入所有实例

    const foo = require("./foo");
    

    这样您就可以通过调用foo.InstanceName来访问每个实例

    如果你想导入特定的实例,

    import MyInstance from "foo";
    

    所以这将从“foo”导入特定实例(Myinstance) 您仍然可以使用上述方法导入所有内容,

    import * as ReferenceName from "foo";
    

    相当于,

    const ReferenceName = require("foo");
    

    【讨论】:

      【解决方案3】:

      TypeScript 2.7 开始,有一个新的 esModuleInterop 标志可用于启用 CommonJS/AMD/UMD 的默认导入。通过在tsconfig.json 中将该标志设置为true,这应该可以按预期工作:

      import foo from 'foo';
      

      【讨论】:

        【解决方案4】:

        正确的方法是继续使用旧的导入语法。新的导入语法仅适用于 ES 模块,旧的导入语法适用于 ES6 之前的模块。两者是不同的,故意的。 import * as foo from 'foo' 导入模块“foo”的所有属性,它不导入默认值作为foo

        From the designer of the feature:

        • 导出默认声明始终声明一个名为 default 的导出成员,并且始终作为 export.default 的赋值发出。换句话说,export default 始终具有 ES 模块语义。为了与 Babel 兼容,我们可以选择在模块具有默认导出时发出 __esModule 标记,但我们实际上不会将该标记用于任何事情。
        • export = 声明,它替换要导出的不同实体来代替模块本身,始终作为对 module.exports 的赋值发出。在使用export = 的模块中有其他导出是错误的。这是现有的 TypeScript 行为。
        • 使用export = 导出另一个模块(内部或外部模块)的模块可以使用新的 ES6 结构导入。特别是,这些模块可以使用方便的解构导入。使用 export = 导出另一个模块的模式在 .d.ts 文件中很常见,这些文件提供内部模块的 CommonJS/AMD 视图(例如 angular.d.ts)。
        • 使用export = 导出非模块实体代替模块本身的模块必须使用现有的import x = require("foo") 语法导入,就像今天一样。

        2016 年更新: TypeScript 编译器在某些时候开始允许 import * as foo from 'legacy-module-foo' 在某些情况下获取旧模块的默认导入。 这违反了 ES6 规范§15.2.1.16“值“*”表示导入请求是针对目标模块的namespace object。”)。

        当您以这种方式导入的遗留模块更新为 ES6 模块时,这些模块的“默认”导入将停止工作(因为 * as foo 导入假定正在导入 命名空间objects),如果您不知道这样做是 TypeScript/SystemJS hack,这可能会非常令人困惑。未来 TypeScript 对 ES 规范的重新调整也有可能导致它们崩溃。

        因此,您可能更愿意继续使用上述遗留导入语法来加载遗留模块,以避免让您自己和其他开发人员在处理您的代码时对 ES6 命名空间导入的工作方式感到困惑,并避免对重大更改造成混淆。

        【讨论】:

        • 谢谢。我已经要求澄清:github.com/Microsoft/TypeScript/issues/…
        • 这已经过时了,对吗?如果我以 ES6 为目标,它 TS 会告诉我 import x = require('foo') 是不允许的
        • 不,它没有过时。在不违反 EcmaScript 规范的情况下,无法在真正的 ES6 模块中导入具有 ES6 import 的非 ES6 模块的默认值。如果你想使用遗留模块,你不能以 ES6 环境为目标,因为在这种情况下,TypeScript 编译器会按原样发出 import 语句,并且 ES 规范没有为默认的 CJS/AMD 模块提供任何规定出口。
        • 这变得更加令人困惑,因为对于从 ES6/Babel 编译的 cjs 模块,新的 import * as <name> from <'module'> 语法仍然有效
        • @CSnover “如果你想使用遗留模块,你不能以 ES6 环境为目标” - 现在这真的很荒谬......谁不需要使用第三方遗留模块?! Babel 以更明智的方式处理它。
        【解决方案5】:

        ES6 模块实际上是 TypeScript 外部模块,具有新的 语法:ES6 模块是单独加载的源文件,可能 导入其他模块并提供一些外部可访问的 出口。 ES6 模块具有几个新的导出和导入 声明。建议使用 TypeScript 库和 应用程序被更新以使用新语法,但这不是 要求。

        Source

        据我了解,这意味着我们鼓励您将自己的 TypeScript 模块迁移到新语法,但继续使用 import foo = require('foo') 来导入实际的 AMD/CommonJS 模块。

        【讨论】:

        • 该声明有点误导,因为它来自 Microsoft。 ES6 与 Typescript 无关。 Typescript 与 ES6 的相似之处在于它也有一个预标准模块系统(就像 Angular 1 有一个预标准模块系统一样)。既然有了正式的标准,固守标准的 TS 模块就很鲁莽了。
        【解决方案6】:

        ES6模块语法对应的语法是:

        import * as foo from 'foo';
        

        基本上将 foo 模块中的所有内容导入到名为 foo 的局部变量中。

        【讨论】:

        • 与此相关的导出语法是什么?当我尝试在旧文件的底部使用 export {Output}; 替换 export = Output 时,我得到了 resolves to a non-module entity and cannot be imported using this construct
        • 我必须警告不要将 import name = require 替换为 import * as name from。如果模块是 ES6 之前的模块,你会遇到问题。如果在需要模块时启动了一些初始化代码,则可能无法使用最新的 Typescript 运行。升级到 Typescript 2.0.3 后,我也遇到过 typescript 警告,不得不将我的 import * 更改为 import require 版本。
        • @user3717718 你能把这些东西发到这里的后续问题:stackoverflow.com/questions/54446403/…。那时候我想过那个。听起来 import blah = require 是最好的,但我担心使用非标准 JS 的东西
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-25
        • 1970-01-01
        • 2015-11-21
        • 1970-01-01
        相关资源
        最近更新 更多