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

问题描述 投票:0回答:2

看起来

import x = require('x')
ES6中是无效语法,并且TypeScript文档中没有任何明确的解释。

typescript ecmascript-6
2个回答
36
投票

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标准。我建议阅读这篇关于 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 模块的本机版本时,您将无法以这种方式导入函数或类


4
投票

TypeScript 中不存在

require()
函数。 ECMAScript 的模块系统使用
import
export
关键字。 Node.js 使用的 CommonJS 模块系统中存在
require
module.exports
exports
关键字。

因此,当您输入

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

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

假设您有

a.ts
x.js
作为源文件。
a.ts
文件导入
x.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.js
exports
module.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 文件中。我们需要将
allowJs
tsconfig.json
属性设置为
true
或在编译项目时使用
--allowJs
标志。

方法一

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

在此示例中,

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

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.exports
插入为
x
,因此这个程序运行得很好。但根据 ECMAScript 规范,
x
不应该是可调用或可构造的(使用
new
)。所以这在语义上是不正确的。

方法三

TypeScript 提供了

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

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 模块密切相关,而且我们使用相同的语法将代码编译为
ECMAScript
CommonJS
模块系统。通过在
esModuleInterop
文件中将
true
选项设置为
tsconfig.json
,TypeScript 编译器会在编译后的 JavaScript 代码中发出适当的辅助函数,以将 default export 功能添加到 CommonJS 模块。

© www.soinside.com 2019 - 2024. All rights reserved.