Importing into Modules

To use items exported from another module, you need to import them. There are a few ways to import named exports, and we will go through them here.

Basic Named Imports

Here is how you can import the functions from the account.js module we created in the previous section:

// script.js
import { deposit, withdraw, getBalance } from "./account.js";

console.log(getBalance());  // 0

deposit(100);
withdraw(20);

console.log(getBalance());  // 80

You do not have to import everything from a module. Import only what you need.

Import Rules

When importing, follow these rules:

  • Import statements must be at the top level (not inside blocks)
  • Import statements must be static (they cannot be conditional)
  • Named imports use curly braces {}; default imports do not
  • Namespace imports use * as Name
  • The from keyword specifies the path to the module (relative or absolute)
  • You cannot import a value that is not exported from the module

Import Aliases with as

Similar to exports, you can use aliases when importing:

import {
  deposit as add,
  withdraw as subtract,
  getBalance as balance,
} from "./account.js";

console.log(balance());  // 0

add(100);
subtract(20);

console.log(balance());  // 80

This is useful when you want to avoid naming conflicts or prefer different names in your code.

Multiple Import Statements

You can use multiple import statements to import from the same module:

import { deposit, withdraw } from "./account.js";
import { getBalance } from "./account.js";

This works, but it is usually cleaner to combine them into a single import.

Namespace Imports with *

You can import everything from a module using the * wildcard:

import * as Account from "./account.js";

console.log(Account.getBalance());  // 0

Account.deposit(100);
Account.withdraw(20);

console.log(Account.getBalance());  // 80

The imported values are stored in an object (here named Account), and you access them using dot notation.

Modules are Not Types

When you import a module, you are importing the values that the module exports. The module itself is not a type.

In our earlier account.js example, there is only ever one instance of the account state. You cannot create different accounts, each with its own balance.

To use Account as a type, you would need to create a class:

// account.js
export class Account {
  #balance = 0;

  constructor(initialBalance = 0) {
    this.#balance = initialBalance;
  }

  deposit(amount) {
    this.#balance += amount;
  }

  withdraw(amount) {
    this.#balance -= amount;
  }

  get balance() {
    return this.#balance;
  }
}

Now you can import the Account class and create different instances:

// script.js
import { Account } from "./account.js";

const johnsAccount = new Account(100);
const marysAccount = new Account();

johnsAccount.deposit(50);
marysAccount.deposit(200);

console.log(johnsAccount.balance);  // 150
console.log(marysAccount.balance);  // 200