Modules page
Learn how to export and import values from a file.
Overview
In this section, you will:
- Export values from a file.
 - Import values from another file.
 - Learn why named exports are preferred over default exports.
 - Import and export functions between modules.
 
Objective 1: Export and import values
A fundamental part of writing code is creating values that you can use across multiple files. Modules are a way of grouping code to be executed within their own scope, opposed to a global scope. Modules give us a way to write DRY code, scope our variables, re-use parts of our code, test our code in discrete units, and avoid writing applications full of dreadful spaghetti code. Let’s break down how to export and import values in TypeScript.
In TypeScript, you can export any type of value: variables, functions, classes, interfaces, etc.
There are two types of exports: default exports and named exports.
Default exports
Imagine we have a config.ts file:
const config = {
  name: "Bitovi Academy",
  url: "https://www.bitovi.com/academy/",
};
export default config;
In the example above, we create a config variable and then use export default to export it.
Then, we could consume the value in another file:
import appConfig from "./config.ts";
const appName = appConfig.name;
In the code above, the appConfig variable is the same as the config variable exported from config.ts.
Note that the appConfig variable name does not need to match the name in the file that has the export.
Named exports
Named exports are called that because there is an explicit name in the file with the export.
Let’s imagine we have a helpers.ts file:
export function constrain(value: number, min: number, max: number): number {
  return Math.min(Math.max(value, min), max);
}
In the example above, we export a constrain function from our helpers.ts file.
We can import the constrain function like so:
import { constrain } from "./helpers.ts";
const constrained = constrain(-18, 0, 100);
In the code above, we can import the constrain function by name from helpers.ts and use it in our code.
Default exports vs. named exports
While you can prefer one style of export over the other, each serves a different purpose.
- Use default exports for the primary output of a module.
 - Use named exports for secondary outputs or when there is no primary output.
 
For example:
- If you have a module called 
AuthProviderthat exports a React component and several helper hooks, the component would be the primary (default) export and the hook would be secondary (named). - If you have a module called 
transformsthat exports the functionsformatPercentandformatCurrency, both of these would be named exports; there is no primary export. 
Importing types
From time to time, you may need to only import the type from another file and not the full implementation.
TypeScript provides a special syntax, import type, which is used specifically to import type declarations.
This can help to make the import intention clearer and can also have some performance benefits during compilation.
Let’s imagine we have a user.ts file:
export type User = {
  age: number;
  name: string;
};
export const createUser = (name: string, age: number): User => {
  return { name, age };
};
In the code above, we defined a User type and a createUser function.
The User type describes the shape of user objects.
We can import just the User type (and use it) like so:
import type { User } from "./user";
import { createUser } from "./user";
const logUser = (user: User): void => {
  console.info(`User: ${user.name}, Age: ${user.age}`);
};
const user = createUser("Alice", 30);
logUser(user);
In the code above, the User type import will not be included in the JavaScript output after compilation (because it’s only used for static type checking by TypeScript).
Use import type whenever you are importing types like interfaces, types, or type aliases from another module and you do not need to import any runtime variables, classes, or functions.
This not only makes your imports cleaner and more specific, but it also optimizes your project’s output size and compilation time.
Setup
✏️ Create src/modules/exporter.ts and update it to be:
function greeter(person: string) {
    return "Hello, " + person;
}
// Exercise: export greeter
✏️ Create src/modules/importer.ts and update it to be:
// Exercise: import greeter
export default function () {
    return greeter("Earth");
}
Verify
✏️ Create src/modules/importer.test.ts and update it to be:
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import getMessageWithGreeting from "./importer";
describe('Importer', () => {
    it('should return a greeting', () => {
        const message = getMessageWithGreeting();
        assert.strictEqual(message, "Hello, Earth", "message should be correct");
    });
});
Exercise
Use your knowledge of named exports and imports to do the following:
- Export 
greeterfromexporter.ts - Import 
greeterinimporter.ts 
Having issues with your local setup? You can use either StackBlitz or CodeSandbox to do this exercise in an online code editor.
Solution
If you’ve implemented the solution correctly, the tests will pass when you run npm run test!
Click to see the solution
✏️ Update src/modules/exporter.ts to be:
export function greeter(person: string) {
  return "Hello, " + person;
}
 
✏️ Update src/modules/importer.ts to be:
import { greeter } from "./exporter"
export default function () {
    return greeter("Earth");
}
 
Having issues with your local setup? See the solution in StackBlitz or CodeSandbox.
Bonus exploration
What does your IDE show when you try to:
- Hover over 
greeter? - Pass a number to 
greeter? 
Next steps
Next, let’s learn how to declare types in TypeScript.