VOOZH about

URL: https://blog.logrocket.com/organize-code-in-typescript-using-modules/

⇱ Organize code in TypeScript using modules - LogRocket Blog


2021-01-13
1297
#typescript
Emmanuel John
32005
πŸ‘ Image

See how LogRocket's Galileo AI surfaces the most severe issues for you

No signup required

Check it out

One of the things I really like about TypeScript is its ability to support modular programing architecture. After years of building JavaScript applications with rapt attention to design patterns and best practices, I’ve found that the ES6 module pattern is essential when considering structure and reusability of software.

πŸ‘ Image

In this article, we will discuss modules, what they are, and why and how to use them to improve the organization of your TypeScript code.

πŸš€ Sign up for The Replay newsletter

The Replay is a weekly newsletter for dev and engineering leaders.

Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.

What are modules?

Modules are a type of design pattern in computer programming used to improve the readability, structure, and testability of code. They are supported by many programming languages including TypeScript. In simplified terms, modules are small pieces of code with independent program functionalities.

Why do we need modules?

A typical software grows gradually as new pieces of functionality are introduced. Structuring and preserving our codebase can be a tedious task initially, but doing the work upfront makes things easier the next time someone works on the codebase.

Without structuring our code, parts of our software can become deeply entangled, making it more difficult to reuse code and to look at any piece of code in isolation. Modules are an incredibly helpful tool for keeping code disentangled and accessible for reuse and testing.

Modules, as a organizational tool for code and its associated functions, allow us to:

  • Encapsulate our code.
  • Explicitly define the list of modules that the current one requires to function.
  • Structure our code in self-contained blocks
  • Test our code easily
  • Define public APIs
  • and more!

In the following sections, we will discuss how to use modules with TypeScript.

Exploring TypeScript modules

Now that we have a shared understanding of what modules are in software development, we can take a deeper dive into TypeScript modules and how to use them.

Given that TypeScript is a superset of JavaScript, it derives most of its concept from JavaScript including the JavaScript modules pattern introduced in ES6. It also uses the same export and import keywords as the JavaScript ES6 modules.

Using export syntax

In TypeScript, a piece of code remains internal to the module and cannot be accessed outside its module until exported. Once exported, the code becomes exposed.

Here is an example using export:

// module-1.ts 

//Private variable
let myApiKey: string = "Secret"; 

//Public variable
export const myPublicKey: string = "Public"; 

export enum MutationType {
 CreateTask = 'CREATE_TASK',
 SetTasks = 'SET_TASKS',
 RemoveTask = 'REMOVE_TASK',
 EditTask = 'EDIT_TASK',
}

// exported interface 
export interface Mutation{ 
 content: string; 
 type: MutationType; 
}

// private function
function logToConsole(mutation: Mutation): void {
 switch (mutation.type) {
 case MutationType.CreateTask:
 console.log(mutation.content);
 ...
 default:
 console.error(mutation.content);
 }
 console.log(message);
}

// exported function
export function log(mutation: Mutation): void {
 logToConsole(mutation);
}

Using import syntax

In TypeScript, an exposed piece of code in one module can be accessible outside its module using import.

Here is an example:

// my-module.ts
import { log, Mutation, MutationType, myPublicKey } from "./module-1";
console.log("Public key: ", myPublicKey);
const deleteTask: Mutation = {
 content: "Delete a task",
 type: MutationType.RemoveTask,
};
const createTask: Mutation = {
 content: "Create a task",
 type: MutationType.CreateTask,
};
log(deleteTask);
log(createTask);

Using TypeScript modules, we can import and export classes, type aliases, var, let, const, and other symbols.

Renaming with import

A very common concept in ES6 modules is renaming import. In TypeScript, it is possible to rename the exposed piece of code upon import using the following syntax:

// my-module.ts
import { publicKey as publicApiKey } from './module-1"

Alternatively, you can use the syntax below to import all of the contents of a module and give it a name of your choice:

// my-module.ts
import * as anyName from './module-1"

Finally, by setting the esModuleInterop option to true in tsconfig.json, you can import CommonJS modules using the syntax below (which is compliant with the ECMAScript specifications):

// my-module.ts
import foo from "someCommonJsModule";

For new TypeScript 3+ projects, the esModuleInterop setting is automatically enabled.


Over 200k developers use LogRocket to create better digital experiences

πŸ‘ Image
Learn more β†’

Renaming with export

It is also possible to use export statements to rename our exposed piece of code using the following syntax:

interface Mutation{ 
 content: string; 
 type: MutationType; 
}

enum MutationType {
 CreateTask = 'CREATE_TASK',
 ...
}
// 1
export {
 Mutation
}
// Renaming export
export {
 Mutation as RenamedMutation
}

In the examples above, the first export simply exports the symbol with its original name, while the second one exports it with a different name, using the as keyword.

Default export

Just as with the JavaScript ES6 modules, each module can have a default export using the following syntax.

// export default function
export default function log(mutation: Mutation): void {
 logToConsole(mutation);
}

The default export syntax can be used alongside the renamed export and export syntax as follows:

// export default function
export default function log(mutation: Mutation): void {
 logToConsole(mutation);
}

function saveMutation(mutation: Mutation): void {
 saveToLocalStorage(mutation);
}

export {
 saveMutation
}

// Renaming export
export {
 saveMutation as RenameSaveMutation
}

Finally, in a module, it is possible to export a single object or function using the export = ... syntax. For example:

//save-module.ts
function saveMutation(mutation: Mutation): void {
 saveToLocalStorage(mutation);
}
export = saveMutation;

Below is the corresponding import syntax when using the export = ... syntax:

//use-save-module.ts
import saveMutation = require("./save-module");
saveMutation(mutationToBeSave);

Please note, however, that this is not the recommended approach. You should only use this import style as a last resort to import an exposed piece of code from a module.

Re-exports

It is also possible to re-export exposed piece of code exported by other modules:

// module-with-re-exports.ts 
export * from "./module-1";

In the preceding code snippet, we did nothing in the module apart from re-exporting all the exposed pieces of code in module-1.ts.

How to use barrels with import and export

What are barrels?

Barrels are a technique used to roll up exports from different modules into a single one, usually called index.ts, to simplify the imports. Barrels thus simply combine the exports of one or more other modules. Barrels are incredibly useful because they let you concentrate on what piece of code you want to use and not on where they are located.

Understanding barrels in context

Barrels can be used tactically to ease the imports of a specific piece of exposed code.

For example, the code snippet below exports the books function, which returns bookList (an array of strings) using the export syntax:

//barrel/book-module.ts
const bookList: string = ["God of War", "Lord of the rings"]
export function books(): string[] {
 return bookList
}

Similarly, the following code snippet exports the cars function, which returns carList (an array of strings) using the export syntax.


More great articles from LogRocket:


//barrel/car-module.ts
const carList: string = ["Ferrari", "BMW"]
export function cars(): string[] {
 return carList
}

Finally, the following code snippet demonstrates how to use barrel to roll up exports from different modules into a single one, usually called index.ts. In this example, we re-export all of the exports from './book-module' and './car-module' respectively:

//barrel/index.ts
export * from './book-module';
export * from './car-module';

Why use barrels?

Without a barrel, a consumer would need two import statements:

//barrel/usage.ts
import { books } from '@/barrel/book-module';
import { cars } from '@/barrel/car-module';

Instead, barrels allow us to simplify imports, like so:

//barrel/usage.ts
import {book, car} from '@/barrel';
let allBooks = books(); //["God of War", "Lord of the rings"]
let allCars = cars(); //["Ferrari", "BMW"]

The code snippet below is also a valid barrel usage.

//barrel/usage.ts
import {book, car} from '@/barrel/index.ts';
let allBooks = books(); //["God of War", "Lord of the rings"]
let allCars = cars(); //["Ferrari", "BMW"]

Conclusion

The importance of modular programming cannot be overemphasized in general software development, although it is tempting to neglect it and allow the parts of our software to become deeply entangled.

In order to build scalable and reusable TypeScript applications, I recommend that you take advantage of TypeScript modules to improve the organization of your application. Doing so will increase code reusability and testability, and help create a better overall structure for your builds.

LogRocket understands everything users do in your web and mobile apps.

πŸ‘ LogRocket Dashboard Free Trial Banner

LogRocket lets you replay user sessions, eliminating guesswork by showing exactly what users experienced. It captures console logs, errors, network requests, and pixel-perfect DOM recordings β€” compatible with all frameworks, and with plugins to log additional context from Redux, Vuex, and @ngrx/store.

With Galileo AI, you can instantly identify and explain user struggles with automated monitoring of your entire product experience.

Modernize how you understand your web and mobile apps β€” start monitoring for free.

πŸ‘ Image
πŸ‘ Image
πŸ‘ Image

Stop guessing about your digital experience with LogRocket

Get started for free

Recent posts:

What is TSRX?: What JSX would look like if it were designed today

TSRX adds first-class control flow, conditional hooks, and scoped styles to React via a TypeScript compiler extension β€” no new framework required.

πŸ‘ Image
Ikeh Akinyemi
Jun 12, 2026 β‹… 6 min read

How to add authentication to a React Native app with Better Auth

Learn how to build a full React Native auth system using Better Auth and Expo β€” with email/password login, Google OAuth, session persistence, and protected routes.

πŸ‘ Image
Chinwike Maduabuchi
Jun 9, 2026 β‹… 13 min read

AI dev tool power rankings & comparison [June 2026]

Compare the top AI development tools and models of June 2026. View updated rankings, feature breakdowns, and find the best fit for you.

πŸ‘ Image
Chizaram Ken
Jun 8, 2026 β‹… 11 min read

How to check username availability at scale with Bloom filters

Learn how Bloom filters reduce database lookups for username availability checks while preserving correctness at scale.

πŸ‘ Image
Rosario De Chiara
Jun 8, 2026 β‹… 6 min read
View all posts

Would you be interested in joining LogRocket's developer community?

Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.

Sign up now