It seems import x = require('x')
is an invalid syntax in es6, and there is no clear explanation in typescript documentation.
Key Differences Between Require and ImportRequire is Nonlexical and Import is Lexical. Requires to stay where they have put the file, and imports get sorted to the top of the file. Import is always run at the very beginning of the file and can't be run conditionally.
Require is Non-lexical, it stays where they have put the file. Import is lexical, it gets sorted to the top of the file. It can be called at any time and place in the program. It can't be called conditionally, it always run in the beginning of the file.
The major difference between require and import , is that require will automatically scan node_modules to find modules, but import , which comes from ES6, won't. Most people use babel to compile import and export , which makes import act the same as require .
Yes, this is acceptable in TypeScript.
import … = require(…)
versus const … = require(…)
At runtime (or once the code is compiled), there is no difference between the two syntaxes, the first one is converted to the second one.
import
:import x = require('x')
This syntax is specific to TypeScript. The constant x
is of type given by some typing defined in the imported package or in a package @types/x
.
const
:const x = require('x')
This is a valid syntax in JavaScript and of course in TypeScript. In TypeScript, the constant x
is of type any
.
import … from …
versus import … = require(…)
How about difference between
import x from 'x'
andimport x = require('x')
The syntax import … from …
is from the ES6 standard. I suggest to read this introduction to ES6 modules and how to import and export them.
But, in short, the syntax import x from 'x'
is equivalent to:
import x = require('x').default
(Notice the .default
member.)
import … = require(…)
to the ES6 syntaxThe ES6 standard states that all exported members can be imported into a single "namespace object module".
Then the closest standard syntax of import x = require('x')
is:
import * as x from 'x'
This syntax currently works well with the TypeScript transpilation because the code is converted to a const … = require(…)
.
However: This syntax should be used only in the context defined by the standard. Because, when your code will use a native version of ES6 modules, you won't be able to import a function or a class that way.
The require()
function doesn't exist in TypeScript. ECMAScript's module system uses import
and export
keywords. The require
, module.exports
, and exports
keywords exist in the CommonJS module system used by Node.js.
So when you type const x = require('x')
, TypeScript is going to complain that it doesn't know what require
is. You need to install @types/node
package to install type definitions for the CommonJS module system in order to work with it from the TypeScript.
├── src/
| ├── a.ts
| └── x.js
└── dist/
├── a.js
└── x.js
Let's imagine you have a.ts
and x.js
as source files. The a.ts
file imports x.js
file. Both these files will be compiled to .js
files that will run on Node. So let's understand how these will look like when compiled to 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'
The x.js
sets exports
and module.exports
to a function that returns MAIN
when called. Since a function is also an object
in JavaScript, we can assign some properties to it. The custom
property is a function that returns CUSTOM
when called.
// src/x.js
exports = module.exports = function() { return 'MAIN'; }
exports.custom = function() { return 'CUSTOM'; }
The src/x.js
is already a .js
file with the CommonJS module syntax. We can import it inside a TypeScript file by using import
syntax. We need to set the allowJs
property of tsconfig.json
to true
or use --allowJs
flag while compiling the project.
// src/a.ts
import x from './x';
console.log( x() ); // === error ===
console.log( x.custom() ); // === error ===
In this example, import x
syntax states that x
is the default export, however, x.js
does not have a default export since that feature lacks in the CommonJS module system. You can allow this by setting the esModuleInterop
option to true
in the tsconfig.json
. So when you try to compile this program, you are going to get the following compilation error.
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`
In this example, import * as x
syntax states that all export members will be stored in the x
object. Hence, x
itself doesn't represent anything, it is just a container that holds all the exports such as x.custom
. However, TypeScript can inter module.exports
as x
and therefore this program works just fine. But according to ECMAScript specifications, x
should not be callable or constructible (using new
). So this isn't semantically right.
TypeScript provides import = require()
and export =
syntax to work with such situations. This syntax is limited to TypeScript only and it can be only used when the module
property is set to CommonJS
in the tsconfig.json
.
The export =
syntax represents a single object that will be exported from the module. By default, a JavaScript module with an export in the form of module.exports
automatically obtain export =
type.
But you can use
exports = function(){ ... }
syntax in a TypeScript or JavaScript file. The TypeScript compiler will convert this syntax intomodule.exports
syntax in the compiled JavaScript code.
// src/a.ts
import x = require( './x' );
console.log( x() ); // `MAIN`
console.log( x.custom() ); // `CUSTOM`
When a module has exports =
type, the ideal way to import it using import = require()
syntax.
I would personally prefer to use import x from
syntax since we can closely relate it with a CommonJS module and also, we compile the code to ECMAScript
and CommonJS
module system using the same syntax. By setting esModuleInterop
option to true
in the tsconfig.json
file, the TypeScript compiler emits appropriate helper functions in the compiled JavaScript code to add the default export feature to a CommonJS module.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With