typescript 中 `import x = require('x')` 和 `const x = require('x')` 之间的区别

Posted

技术标签:

【中文标题】typescript 中 `import x = require(\'x\')` 和 `const x = require(\'x\')` 之间的区别【英文标题】:Difference between `import x = require('x')` and `const x = require('x')` in typescripttypescript 中 `import x = require('x')` 和 `const x = require('x')` 之间的区别 【发布时间】:2019-03-03 05:54:09 【问题描述】:

似乎import x = require('x')在es6中是无效语法,打字稿文档中也没有明确的解释。

【问题讨论】:

import 导入,const 定义一个常量变量.... import x from 'x'import x = require('x') 的区别如何? Typescript import/as vs import/require?的可能重复 insights.untapt.com/webpack-import-require-and-you-3fd7f5ea93c0 【参考方案1】:

Q1:import … = require(…)const … = require(…)

在运行时(或代码编译后),两种语法没有区别,第一种转换为第二种。

import:

import x = require('x')

此语法特定于 TypeScript。常量x 的类型由导入包或包@types/x 中定义的某些类型给出。

const:

const x = require('x')

这是 javascript 中的有效语法,当然在 TypeScript 中也是如此。在 TypeScript 中,常量 x 的类型为 any

Q2:import … from …import … = require(…)

import x from 'x'import x = require('x') 的区别呢

import … from … 的语法来自 ES6 标准。我建议阅读 this introduction 到 ES6 模块以及如何导入和导出它们。

但是,简而言之,import x from 'x' 的语法等价于:

import x = require('x').default

(注意.default 成员。)

如何将import … = require(…) 转换为 ES6 语法

ES6 标准规定所有导出的成员都可以导入单个“命名空间对象模块”

那么import x = require('x')最接近的标准语法是:

import * as x from 'x'

此语法目前适用于 TypeScript 转译,因为代码已转换为 const … = require(…)

但是:此语法只能在标准定义的上下文中使用。因为,当您的代码将使用原生版本的 ES6 模块时,您将无法以这种方式导入函数或类

【讨论】:

【参考方案2】:

require() 函数在 TypeScript 中不存在。 ECMAScript 的模块系统使用importexport 关键字。 Node.js使用的CommonJS模块系统中存在requiremodule.exportsexports关键字。

所以当你输入 const x = require('x') 时,TypeScript 会抱怨它不知道 require 是什么。您需要安装 @types/node 包来安装 CommonJS 模块系统的类型定义,以便从 TypeScript 中使用它。

├── src/
|   ├── a.ts
|   └── x.js
└── dist/
    ├── a.js
    └── x.js

假设您有a.tsx.js 作为源文件。 a.ts 文件导入 x.js 文件。这两个文件都将编译为.js 将在 Node.js 上运行的文件。那么让我们来了解一下这些编译成 JavaScript 后的样子。

// dist/x.js
exports = module.exports = function()  return 'MAIN'; 
exports.custom = function()  return 'CUSTOM'; 

// dist/a.js
const x = require( 'x.js' );
console.log( x() ); // 'MAIN'
console.log( x.custom() ); // 'CUSTOM' 

x.jsexportsmodule.exports 设置为调用时返回MAIN 的函数。由于函数在 JavaScript 中也是 object,因此我们可以为其分配一些属性。 custom 属性是一个在调用时返回 CUSTOM 的函数。

// src/x.js
exports = module.exports = function()  return 'MAIN'; 
exports.custom = function()  return 'CUSTOM'; 

src/x.js 已经是一个具有 CommonJS 模块语法的 .js 文件。我们可以使用 import 语法将其导入到 TypeScript 文件中。我们需要在编译项目时将tsconfig.jsonallowJs属性设置为true或使用--allowJs标志。

方法一

// src/a.ts
import x from './x';
console.log( x() ); // === error ===
console.log( x.custom() ); // === error ===

在此示例中,import x 语法指出 x默认导出,但是,x.js 没有默认导出,因为 CommonJS 模块系统中缺少该功能。您可以通过将tsconfig.json 中的esModuleInterop 选项设置为true 来允许此操作。所以当你尝试编译这个程序时,你会得到如下的编译错误。

a.ts:1:8 - error TS1259: Module '"./x"' can only be default-imported using the 'esModuleInterop' flag

1 import x from './src/q';
         ~

  src/q.js:1:11
    1 exports = module.exports = function()  return "MAIN"; 
                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    This module is declared with using 'export =', and can only be used with a default import when using the 'esModuleInterop' flag.

方法二

// src/a.ts
import * as x from './x';
console.log( x() ); // `MAIN`
console.log( x.custom() ); // `CUSTOM`

在此示例中,import * as x 语法规定所有导出成员都将存储在x 对象 中。因此,x 本身并不代表任何东西,它只是一个包含所有导出的容器,例如x.custom。但是,TypeScript 可以将 module.exportsx 交互,因此该程序可以正常工作。但根据 ECMAScript 规范,x 不应该是可调用或可构造的(使用 new)。所以这在语义上是不正确的。

方法三

TypeScript 提供 import = require()export = 语法来处理这种情况。此语法仅限于 TypeScript,并且只能在 tsconfig.json 中的 module 属性设置为 CommonJS 时使用。

export = 语法表示将从模块中导出的单个对象。默认情况下,以module.exports 形式导出的JavaScript 模块会自动获取export = 类型。

但您可以在 TypeScript 或 JavaScript 文件中使用 exports = function() ... 语法。 TypeScript 编译器会将此语法转换为已编译的 JavaScript 代码中的module.exports 语法。

// src/a.ts
import x = require( './x' );
console.log( x() ); // `MAIN`
console.log( x.custom() ); // `CUSTOM`

当模块具有exports = 类型时,使用import = require() 语法导入它的理想方式。


我个人更喜欢使用import x from 语法,因为我们可以将它与CommonJS 模块密切相关,而且我们使用相同的语法将代码编译为ECMAScriptCommonJS 模块系统。通过在 tsconfig.json 文件中将 esModuleInterop 选项设置为 true,TypeScript 编译器会在编译的 JavaScript 代码中发出适当的帮助函数,以将 默认导出 功能添加到 CommonJS 模块。

【讨论】:

以上是关于typescript 中 `import x = require('x')` 和 `const x = require('x')` 之间的区别的主要内容,如果未能解决你的问题,请参考以下文章

将 Angular 1.x 与 TypeScript 1.5 和 SystemJS 一起使用

在 TypeScript 中使用 import/require 来获取接口声明

TypeScript 中的 Import 和 require 有啥不同?

TypeScript - import ... 和 import ... 之间的区别(带花括号)

不能在模块 Electron React Typescript 之外使用 import 语句

Typescript、React、Electron:不能在模块外使用 import 语句