TypeScript Import and Export

In modern TypeScript development, you rarely write your entire application in a single file. As your project grows, it becomes difficult to manage thousands of lines of code. This is where modules come in. By using import and export, you can break your code into smaller, reusable pieces.

This modular approach keeps your global namespace clean, prevents naming conflicts, and makes your code significantly easier to test and maintain. Think of a module as a private container: nothing inside it is visible to the outside world unless you explicitly "export" it.

Developer Tip: Modularizing your code doesn't just help with organization; it also allows modern build tools (like Webpack or Vite) to perform "tree-shaking," which removes unused code from your final production bundle.

 

What is Import and Export?

  1. Export: This keyword acts as a "public" modifier for your module. It tells TypeScript which functions, variables, classes, or interfaces should be accessible to other files in your project.
  2. Import: This keyword allows you to pull those exported elements into a different file so you can use them.
Best Practice: Group related logic into a single module. For example, keep all your authentication logic in auth.ts and all your mathematical utilities in math-utils.ts.

 

Exporting in TypeScript

1. Named Exports

Named exports are the most common way to share code. They allow you to export multiple items from a single file by prefixing them with the export keyword. When you import them, you must use the exact name they were given.

Example: Exporting Variables, Functions, and Classes

// file: math.ts

export const pi = 3.1415;

export function add(x: number, y: number): number {
  return x + y;
}

export class Calculator {
  static multiply(x: number, y: number): number {
    return x * y;
  }
}
  • In this example, pi, add(), and Calculator are exported independently. Any file importing math.ts can choose to take one, two, or all of these items.
Common Mistake: Forgetting that exports are case-sensitive. If you export const MyConfig, you cannot import it as myConfig.

2. Default Exports

A default export is used when a module has one primary purpose or "main" piece of code. Each file can have only one default export.

Example: Default Export

// file: multiply.ts

export default function multiply(x: number, y: number): number {
  return x * y;
}
  • Here, multiply is the default export. This is common when a file contains a single class or a specific utility function.
Watch Out: While default exports are easy to use, they can make refactoring harder because the importing file can name the import whatever it wants, making it difficult to search for usages across a large codebase.

 

Importing in TypeScript

1. Importing Named Exports

To import named exports, you wrap the specific names in curly braces { }. The path to the file usually omits the .ts extension.

Example: Importing Named Exports

// file: app.ts
import { pi, add, Calculator } from './math';

console.log(`Pi: ${pi}`);
console.log(`Sum: ${add(5, 3)}`);
console.log(`Product: ${Calculator.multiply(5, 3)}`);
Developer Tip: Most modern IDEs like VS Code will automatically add these import statements for you as soon as you start typing the name of an exported function or class.

2. Importing Default Exports

When importing a default export, you do not use curly braces. You can also give the import any name you prefer, though it's best practice to keep it consistent with the filename.

Example: Importing Default Export

// file: app.ts
import multiply from './multiply';

console.log(`Product: ${multiply(5, 3)}`);
Common Mistake: Putting curly braces around a default import. Writing import { multiply } from './multiply' will fail if multiply was exported as default.

3. Renaming Imports

Sometimes you might encounter a naming conflict (e.g., two different modules both export a function called initialize). You can use the as keyword to rename an import locally.

Example: Renaming Imports

// file: app.ts
import { add as sum, Calculator } from './math';

// Now we use 'sum' instead of 'add'
console.log(`Sum: ${sum(5, 3)}`);

4. Importing All Exports from a Module

If a module exports many items and you want to use all of them without listing every name, use the * as syntax. This bundles everything into a single object.

Example: Importing All Exports

// file: app.ts
import * as MathUtils from './math';

console.log(`Pi: ${MathUtils.pi}`);
console.log(`Sum: ${MathUtils.add(10, 2)}`);
Watch Out: Using import * can sometimes hinder "tree-shaking" in older build tools, potentially including code in your final bundle that you aren't actually using. Use it sparingly for large utility libraries.

 

Re-exporting from Modules

Re-exporting is a powerful technique used to create "Barrel Files" (usually named index.ts). This allows you to gather exports from several files and expose them from a single point.

Example: Creating a "Barrel" File

// file: utilities/index.ts
export * from './math';
export * from './string-helpers';
export { default as logger } from './logger';
  • By doing this, other developers only need to import from ./utilities instead of digging through various subfolders.
Best Practice: Use barrel files (index.ts) in your folders to provide a clean public API for your modules. This simplifies import paths for anyone using your folder's logic.

 

Module Resolution in TypeScript

Module resolution is the process the TypeScript compiler uses to figure out what a "relative path" or a "module name" actually refers to on your hard drive.

  1. Classic Resolution: An older strategy used for backward compatibility. Rarely used in modern projects.
  2. Node Resolution: Mimics how Node.js looks for files. It checks node_modules, looks for package.json files, and tries to find index.ts or index.js automatically if a folder is imported.

You can control how TypeScript finds your files by adjusting the moduleResolution and baseUrl settings in your tsconfig.json file.

 

Summary

  • Exporting: Sharing variables or logic using export (named) or export default.
  • Importing: Bringing shared logic into a file using import { name } or import name.
  • Named Exports: Best for utility files with many small functions; requires curly braces.
  • Default Exports: Best for files that do one main thing; no curly braces required.
  • Renaming: Use as to avoid naming collisions between different modules.
  • Re-exporting: Using a central file (barrel file) to simplify the import experience for others.
  • Module Resolution: The logic TypeScript uses (usually Node style) to find your files.

By mastering import and export, you move from writing "scripts" to building professional, scalable TypeScript applications.