头图

Modules

JavaScript has a long history of dealing with modular code. Since TypeScript came out in 2012, it has implemented support for many of these formats, but over time, the community and JavaScript specifications have merged into a format called ES modules (or ES6 modules). You may know it is import/export syntax.

ES Modules were added to the JavaScript specification in 2015 and will be widely supported in most web browsers and JavaScript runtimes by 2020.

For the focus, the manual will cover ES modules and their popular precursor CommonJS module.exports = syntax, you can find information about other module modes in the reference section under modules.

How JavaScript Modules are Defined

In TypeScript, just like in ECMAScript 2015, any file that contains top-level imports or exports is considered a module.

Conversely, files without any top-level import or export declarations are considered scripts, and their contents are available globally (and therefore also available to modules).

Modules are executed in their own scope, not in the global scope. This means that variables, functions, classes, etc. declared in the module are not visible outside the module unless they are explicitly exported using one of the export forms. On the contrary, if you want to use variables, functions, classes, interfaces, etc. exported from different modules, you must use one of the import forms to import them.

Non-module

Before we start, it's important to understand what TypeScript considers as modules. The JavaScript specification states that any JavaScript file that has no export or top-level await should be treated as a script rather than a module.

In the script file, the variables and types are declared in the shared global scope, and it is assumed that you will use the --outFile compiler option to concatenate multiple input files into one output file, or use multiple
\<script> Mark your HTML to load these files (in the correct order!).

If you have a file that does not currently have any import or export, but you want to be treated as a module, please add the following line:

export {};

This will change the file to a module that does not export anything. Regardless of your module goals, this syntax is valid.

ES Module syntax

The file can declare the main export through export default:

// @filename: hello.ts
export default function helloWorld() {
  console.log("Hello, world!");
}

This is then imported via:


import hello from "./hello.js";
hello();

In addition to the default export, you can also export multiple variables and functions by omitting the default export:

// @filename: maths.ts
export var pi = 3.14;
export let squareTwo = 1.41;
export const phi = 1.61;

export class RandomNumberGenerator {}

export function absolute(num: number) {
  if (num < 0) return num * -1;
  return num;
}

Import with braces in another file:

import { pi, phi, absolute } from "./maths.js";

console.log(pi);
const absPhi = absolute(phi);

You can also use import alias syntax:


import { pi as π } from "./maths.js";

console.log(π);

You can put all exported objects into a namespace with * as the name:

// @filename: app.ts
import * as math from "./maths.js";

console.log(math.pi);
const positivePhi = math.absolute(math.phi);

What are the consequences of importing a file directly?

// @filename: app.ts
import "./maths.js";

console.log("3.14");

In this case, the import does nothing. However, all code in maths.ts has been evaluated, which may trigger side effects that affect other objects.

TypeScript has enhanced the import syntax, you can only import the type definition in the module.

// @filename: animal.ts
export type Cat = { breed: string; yearOfBirth: number };
'createCatName' cannot be used as a value because it was imported using 'import type'.
export type Dog = { breeds: string[]; yearOfBirth: number };
export const createCatName = () => "fluffy";

// @filename: valid.ts
import type { Cat, Dog } from "./animal.js";
export type Animals = Cat | Dog;

// @filename: app.ts
import type { createCatName } from "./animal.js";
const name = createCatName();

TypeScript’s Module Resolution Options

Module parsing is the process of obtaining a string from an import or require statement and determining which file the string refers to.

TypeScript includes two parsing strategies: Classic and Node. Classically, when the compiler flag module is not the default value of commonjs, it is included for backward compatibility. The Node strategy replicates the way Node.js works in CommonJS mode, and additionally checks .ts and .d.ts.

There are many TSConfig flags that affect the module strategy in TypeScript: moduleResolution, baseUrl, paths, rootDirs.

For complete details on how these strategies work, you can consult the module solution.

TypeScript’s Module Output Options

There are two options that affect the JavaScript output emitted:

  • target determines which JS features are downgraded (converted to run in an older JavaScript runtime) and which remain unchanged
  • module: A module that determines which codes are used to interact between modules

The target you use depends on the features available in the JavaScript runtime in which you want to run TypeScript code. This may be: the oldest web browser you support, the lowest version of Node.js that you want to run or may come from, comes from the unique constraints of your runtime—for example, Electron.

All communication between modules is carried out through the module loader, and the compiler flags the module to determine which one to use. At runtime, the module loader is responsible for locating and executing all dependencies of the module before execution.

For example, this is a TypeScript file that uses ES module syntax, showing several different options for the module.

Here is the original TypeScript file:

import { valueOfPi } from "./constants.js";

export const twoPi = valueOfPi * 2;

The following is the ES2020 output:

import { valueOfPi } from "./constants.js";
export const twoPi = valueOfPi * 2;

Here is CommonJS:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.twoPi = void 0;
const constants_js_1 = require("./constants.js");
exports.twoPi = constants_js_1.valueOfPi * 2;

Here is UMD:

(function (factory) {
    if (typeof module === "object" && typeof module.exports === "object") {
        var v = factory(require, exports);
        if (v !== undefined) module.exports = v;
    }
    else if (typeof define === "function" && define.amd) {
        define(["require", "exports", "./constants.js"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.twoPi = void 0;
    const constants_js_1 = require("./constants.js");
    exports.twoPi = constants_js_1.valueOfPi * 2;
});

注销
1k 声望1.6k 粉丝

invalid