avatarJennifer Fu

Summary

The provided content is a comprehensive guide on how to use export and import modules in JavaScript and TypeScript, detailing various methods for exporting and importing variables, functions, classes, and other entities.

Abstract

The article serves as an extensive guide for developers on the use of ES6 modules in JavaScript and TypeScript. It covers the syntax and usage of export and import statements, demonstrating how to export and import individual variables, functions, classes, as well as type definitions, interfaces, and enums in TypeScript. The guide also explains how to use default exports, re-export modules, and the concept of destructuring in the context of module exports. It emphasizes the benefits of modular programming, such as encapsulation and code organization, and provides practical examples to illustrate the concepts discussed.

Opinions

  • The author suggests that ES6 modules are a significant addition to JavaScript, enhancing the language's ability to write complex applications.
  • The guide advocates for the use of let and const over var for variable declarations in exports, aligning with modern JavaScript best practices.
  • The article promotes the idea of selective imports, allowing developers to import only what is needed, which can lead to more efficient and maintainable code.
  • The author implies that TypeScript's module system is an extension of JavaScript's, offering additional constructs like interfaces and enums for type safety.
  • The guide encourages the use of default exports for simplicity in certain scenarios, while also acknowledging the flexibility provided by named exports.
  • The article highlights the utility of re-exporting, which allows for the aggregation of multiple modules into a single, convenient import point.
  • The author expresses a preference for explicit naming in imports and exports, which can improve code readability and reduce ambiguity.
  • The guide concludes with a pedagogical approach, inviting readers to engage with the material by posing a question and providing further reading through the author's other publications.

A Handy Guide to Export and Import Modules for JavaScript and TypeScript

How to include exactly what you need to get the job done

Photo by Fatos Bytyqi on Unsplash.

ECMAScript is a scripting-language specification standardized by Ecma International in ECMA-262 and ISO/IEC 16262. JavaScript is one of the most popular implementations of ECMAScript. Starting from the first edition in June 1997, JavaScript has evolved to provide more functionality and become easier to use. ES6 or ES2015 is a revolutionary version. It adds a significant amount of new syntaxes for writing complex applications. One of the prominent additions is modules.

An ES6 module is a JavaScript file. It is executed within its own scope — not in the global scope. Variables, functions, and classes that are declared in a module are not sharable between modules unless they are explicitly exported and imported.

  • export: A statement to export primitive values, objects, functions, or classes from the module for the purpose of being used by other modules.
  • import: A statement to use primitive values, objects, functions, or classes that are exported from another module. Typically, an import is static, but it can be dynamic too.

TypeScript has also adopted ES6 modules. There are more things to export and import, such as interfaces, types, namespaces, and enums.

Exports and imports are closely connected. We will give some examples below to see how to write export and import statements.

Export and Import Statements: Example 1

Variables can be exported individually via putting export in front of each declaration.

export let a, b, c, d, e, f, g, h;
export let i, j, k, l, m, n, o, p;
export let q;
a = 1; // a primitive value of number
b = null; // a primitive value of null
c = undefined; // a primitive value of undefined
d = Symbol(); // a primitive value of Symbol
e = [1, 2, 3]; // an array
f = { // a plain object
  a: 1,
  b: 2,
  c: 3
};
g = Date; // a Date object
h = new Map(); // a Map object
i = new Set(); // a Set object
j = new Promise((resolve) => { // a Promise object
  resolve(5);
});
k = function() { // an anonymous function
};
l = function myFunction () { // a named function
};
m = () => true; // an arrow function
n = function* myGenerator(i) { // a generator function
  yield i;
}
o = async function myAsync() { // an async function
  await n;
}
p = class { // a class with no class name
};
q = class MyClass { // a class with a class name
};

These exports can be selectively imported by specifying variable names:

import { a, b, c } from './myExports';
----------------------- or ---------------------
import { k } from './myExports';
----------------------- or ---------------------
import { a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q } from './myExports';

With many import items, there is an option to import the whole thing as a module and then use the module name.

For the following import statement, everything is imported as myImportModule:

import * as myImportModule from './myExports';

Then the code can use the exported items as myImportModule.a, myImportModule.b, etc.

Export and Import Statements: Example 2

Variables can be exported individually via putting export in front of each declaration with a value assignment.

export var a = 1; // It is recommended to use let or const
                  // var is kept for backwards compatibility
export let b = null; // a variable initialized to null
export const c = undefined; // a constant variable

These exports can be imported as follows:

import { a, b, c } from './myExports';

Export and Import Statements: Example 3

Function and class definitions can be exported directly by putting export in front of their definitions.

export function myFunction() {}
export class myClass {}

These exports can be imported as follows:

import { myFunction, myClass } from './myExports';

In addition, TypeScript supports exporting types, interfaces, and enums.

export type NumberOrString = number | string; // a type example, union is supported by type, but not by interface
export interface Base {} // a base interface example
export interface Child extends Base {} // an extended interface example, inheritance is supported by interface, not by type
export enum DayOfWeek { // an enum example
  Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday
}

These exports can be imported as follows:

import { NumberOrString, Base, Child, DayOfWeek } from './myExports';

TypeScript has export = syntax. It specifies a single object that is exported from the module. This can be a function, class, interface, namespace, or enum. The following is how React is being exported by DefinitelyType.

export = React;
export as namespace React;

Export and Import Statements: Example 4

Variables can be exported as a list.

const dayDefinitions = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
const daysOfWeek = dayDefinitions.length;
let currentDayIndex = 3;
export { dayDefinitions, daysOfWeek, currentDayIndex };

These exports can be imported as follows:

import { dayDefinitions, daysOfWeek, currentDayIndex } from './myExports';

Export and Import Statements: Example 5

Variables can be exported as a list. In addition, items on the list can be renamed. The new name is also called an alias.

const a = 1, c = undefined;
let b = null;
export { a as NUMBER_ONE, b as newNameForB, c as undefined_value};

These exports can be imported as follows:

import { NUMBER_ONE, newNameForB, undefined_value } from './myExports';

In addition, an importer can rename the item with a new alias. Here is an example of an alias of an alias:

import { NUMBER_ONE as myA, newNameForB as myB, undefined_value as myC} from './myExports';

Export and Import Statements: Example 6

Destructure assignments can be used for export too. In addition, these kinds of exports can be selectively renamed.

let person1 = {
  name: 'John',
  age: 10,
  grade: 5
};
let person2 = ['Lisa', 12, 7];
// name is renamed to nameOfPerson1
// age is renamed to ageOfPerson1
export const { name: nameOfPerson1, age: ageOfPerson1 } = person1;
// first item is renamed to nameOfPerson2
// second item is renamed to ageOfPerson2
export const [ nameOfPerson2, ageOfPerson2 ] = person2;

These exports can be imported as follows:

import { nameOfPerson1, ageOfPerson1, nameOfPerson2, ageOfPerson2 } from './myExports';

Export and Import Statements: Example 7

There are two types of exports: default exports and named exports. Each module can have at most one default export in a module, but it can have multiple named exports.

Only expressions, functions, or classes are allowed to be a default export. The name of a default export is not required.

From examples 1 through 6, all exports are named export. Here, we’ll look at some examples of a default export.

export default 5;
----------------------- or ---------------------
const a = 5;
export { a as default };
----------------------- or ---------------------
const a = 5;
export default a;
----------------------- or ---------------------
let a;
export default a = 5;
----------------------- or ---------------------
export default function() {};
----------------------- or ---------------------
export default class {};

When a default export is imported, the importer can name it anything.

import { default as X } from './myExports';
----------------------- or ---------------------
import X from './myExports';

Does the following line look familiar?

import React from 'react';

In fact, importing a default export and other items can be mixed. Is the following another familiar line?

import React, { useCallback, useState, useEffect } from 'react';

Examples of Re-Exporting

Modules can be exported or partially re-exported by a new module.

export * from './myExports'; // re-export everything
export {myFunction} from './myExports'; // partial re-export

Re-exporting aggregates all export statements together into a new module as a single source.

If we have a reExports.js defined as follows:

export { a, b, c, d } from './myExports1';
export { e, f } from './myExports2';
export { g, h, i} from './myExports3';

It can be imported neatly as:

import { a, b, c, d, e, f, g, h, i } from './reExports';

Re-exporting works for both JavaScript and TypeScript.

A small quiz to finish things off: Do you know why the following code complains that myFunction is not defined?

export {myFunction} from './myExports';
myFunction();

It is because the re-export statement does not make it imported locally. The following code would fix the issue:

import {myFunction} from './myExports';
export {myFunction} from './myExports';
myFunction();

Thanks for reading. I hope this was helpful. If you have any questions, feel free to leave a response. You can see my other Medium publications here.

Typescript
JavaScript
Programming
React
Nodejs
Recommended from ReadMedium