Skip to content

Imports and Exports in JavaScript Typescript

Ole Anders Stokker edited this page Apr 14, 2019 · 6 revisions

There are a lot of ways to do both imports and exports in both JavaScript and Typescript, they even differ a little bit between the languages.

CommonJS: require();

Commonly used in NodeJS, and mostly just in JavaScript. Kinda seen as 'the old way'.

It is also not available in the browser!

importing

Importing with CommonJS is done by using the require() function built into NodeJS.

example:

// It supports importing the main module. E.g luxon.
const luxon = require('luxon');

const date = luxon.DateTime.local();

// You can also destructure it to its' inne modules.
const { DateTime } = require('luxon');

const date = DateTime.local();

Imports in CommonJS can be done at runtime, which is lacking in most other systems. This is because it it only wirks in NodeJS.

This can help us with only loading large/expensive modules when they are needed, instead of keeping all of it in memory. It can also help with loading modules only if the system we are currently running on is missing a feature, where other systems might have it. See polyfills and ponyfills // TODO: create article about them..

// Modules can be loaded after the system has started running, and used conditionally
if (foo) {
	const { DateTime } = require('luxon');
}

exporting

Default export:

exporting a single variable/object/function

// numToStr.js
module.exports = (num) => String(num);

// Can be used like this:
const numToStr = require('numToStr');

const str = numToStr(5); // '5'
Using an object literal to export multiple things as default
// numToStr.js
module.exports = {
	example: 5,
    numToStr: (num) => String(num),
};

// Can be used like this
const { example, numToStr } = require('numToStr');

const str = numToStr(example); // '5'

Named exports:

// numToStr.js
exports.example = 5;
exports.numToStr = (str) => String(num);

// Can be used like this
const { example, numToStr } = require('numToStr');
const str = numToStr(example); // '5'

Usage in TypeScript

This style of importing and exporting is not used a lot i TypeScript by itself. TypeScript mostly uses Es modules (described below) with a little twist.

Compiling Typescript for use with NodeJS will however be transpiled to CommonJS exports and require statements when it is compiled with the TypeScript Compiler (tsc).

ES modules: import, export

A newer version of importing things in JavaSript and TypeScript, which is used a lot with front-end code is ES modules.

Both imports and exports are node with keywords instead of a built in function, like CommonJS does it.

importing

Importing a default export

// Importing a default export
import luxon from 'luxon';

const date = luxon.DateTime.local();
Naming a default export

When importing a default export, you can call it whatever you want. It is common to name it after the package you are importing, but it is not strictly necessary.

// This is valid, but please don't.
import Angular from 'react';

Importing other exported members

import { DateTime } from 'luxon';

const date = DateTime.local();

Differences from CommonJS:

Since ES modules is not bound by the regular syntax of JavaScript, it can do a few things that the require function can't do.

An example is importing both the default export and other exported member at the same time. This is often used in React files, as due to JSX/TSX. Read more about that here // TODO: write article about jsx/tsx.

// You'll see a lot of imports like this, where both the default and useState are imported.
import React, { useState } from 'react';

const Foo = () => {
	const [value, setValue] = useState(...);
	return (
		...
	);
};

// It would be that same as doing this
import React from 'react';

const Foo = () => {
	const [value, setValue] = React.useState(...);
	return (
		...
	);
};

Synthetic default imports

I kinda lied when I said default imports are written like this:

import React from 'react';

JavaScript is an ever developing language, and due to its' users often adopting standards before they are finalized (Read more about TC39 and the ECMAScript standard TODO: Write article about TC39), splits may occur in how things are done. (I need to read more about the reasoning for why and how this actually works...).

For TypeScript, default imports are actually written like this:

import * as React from 'react';
// Or
import * as React, { useState } from 'react';

import as another name

Sometimes you may end up with name conflicts, or just want a more specific name for the imported module depending on the context of its' usage.

This is what import as is for.

Example:

// If you just want to fuck shit up
import { useContext as useState } from 'react';

// or an actual valid use case:
import { routes as eventRoutes } from 'events/routes';
import { routes as articleRoutes } from 'article/routes';
// In this case we avoid a name conflict, while providing more context to the object we imported.

exporting

Default exports:

// numToStr.js
export default (num) => String(num);

// Used like this
import numToStr from 'numToStr';
const str = numToStr(5); // '5'

Named exports:

// numToStr.js
export const example = 5;
export const numToString = (num) => String(num);

// Used like this:
import { example, numToStr } from 'numToStr';
const str = numToStr(exampe);

Assinging to an export

// numToStr.js

const example = 5;
export example;

export const numToStr = (num) => String(num);
export default numToStr;

// Can be imported like this:
import numToStr, { example } from 'numToStr';
// Or like this:
import { example, numToStr } from 'numToStr';

Webpack

Webpack kinda does it own thing here. It reads both versions of imports, but bundles the entire thing into one large single file for, since the web browser cant read files from the web in the same way your computer does.

The browser needs to load the files over the internet, which takes time. That is why we have async dynamic imports.

const foo = await import('foo');

They are however not really usable in that way yet, but works half way Read more about Webpack Bundle splitting and dynaic imports here // TODO: Write article about that...