TypeScript · Projects

Modules

Real TypeScript projects span hundreds of files. This lesson covers how types travel between them and how TypeScript understands JavaScript libraries that were not written in TypeScript.

Advanced 5 min Lesson 23 of 29Examples target TypeScript 5.x with "strict": true.
0/29 in TypeScript
On this page · 5 min · Advanced

Learning objectives#

  • Export and import types and values
  • Use import type for type-only imports
  • Install type definitions from @types
  • Understand .d.ts declaration files
  • Configure path aliases

Explanation#

TypeScript uses standard ES modules: export interface User, export function, import { User } from "./models/user".

import type { User } imports only the type. It is guaranteed to be removed from the JavaScript output, avoiding accidental runtime imports and circular-dependency problems.

A .d.ts (declaration) file contains only types describing JavaScript code. Libraries ship them so TypeScript knows their APIs.

Libraries without built-in types often have community types: npm i -D @types/express. If none exist, write a small declare module "lib-name" yourself.

Path aliases (paths in tsconfig, also configured in your bundler) replace ../../../models with @/models.

Syntax#

TypeScript Illustrative
// models/user.ts
export interface User { id: number; name: string }


// services/api.ts
import type { User } from '../models/user';

Code example: Typed modules across a project#

TypeScriptproject files Illustrative
// ── src/models/product.ts ───────────────
export interface Product {
  id: number;
  name: string;
  price: number;
}
export const CURRENCY = 'INR';


// ── src/services/products.ts ────────────
import type { Product } from '@/models/product';   // type-only import
import { CURRENCY } from '@/models/product';       // value import


export async function getProducts(): Promise<Product[]> {
  const res = await fetch('/api/products');
  return res.json();
}
export const label = (p: Product) => `${p.name} — ${p.price} ${CURRENCY}`;


// ── src/types/confetti.d.ts ─────────────
declare module 'tiny-confetti' {
  export default function confetti(options?: { particles?: number }): void;
}


// ── tsconfig.json (excerpt) ─────────────
// "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["src/*"] } }


// ── terminal ────────────────────────────
// npm i express && npm i -D @types/express
Expected output
Types flow between files, the Product import disappears from the compiled JavaScript, the untyped tiny-confetti library gets a hand-written declaration, and @/ imports resolve to src/.

This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.

Step-by-step explanation#

  1. product.ts exports an interface (type) and a constant (value).
  2. import type brings in Product only for type checking.
  3. The value CURRENCY is imported normally because it is needed at runtime.
  4. confetti.d.ts declares the shape of an untyped JavaScript library.
  5. The paths setting maps @/ to src/ so imports stay short.
  6. @types/express adds types for a library written in JavaScript.

Real-world use case#

Teams keep shared models in a models/ or types/ folder (or even a shared package used by both front end and back end) so client and server agree on data shapes.

Common mistakes#

“Could not find a declaration file for module”

Install @types/<library> or add a declare module "<library>" file.

Aliases only in tsconfig

tsconfig paths only affect type checking. Configure the same alias in Vite/webpack/Node, or imports fail at runtime.

Importing types as values

With isolatedModules/verbatimModuleSyntax, importing a type without type may error. Use import type for types.

Best practices#

  • Use import type for type-only imports
  • Keep shared types in a dedicated folder or package
  • Prefer libraries that ship their own types
  • Mirror path aliases in your bundler config

Remember this#

Same import/export as JavaScript — types travel too.

import type = “only for the checker, erase it afterwards”.

.d.ts = a type manual for JavaScript code. @types/x = community manuals.

Practice exercise#

Your task: You install the JS library "slugify-lite" and get “Could not find a declaration file”. Write a declaration for its default export slugify(text: string): string.

Need a hint?
Create src/types/slugify-lite.d.ts with declare module.
Show solution
TypeScript Illustrative
// src/types/slugify-lite.d.ts
declare module 'slugify-lite' {
  export default function slugify(text: string): string;
}

Mini quiz#

Modules quizMultiple choice Question 1 of 3

What does import type guarantee?

Score so far: 0/0

Want more? Practise all TypeScript MCQs · TypeScript interview questions

My notes#

Saved in this browser.

Progress is saved in this browser. Sign in to sync.