Declaration Files & DefinitelyTyped

TypeScript · Lesson 22 of 28 7 min read Updated

When you call "Pune".toUpperCase() or document.querySelector(), TypeScript knows their types even though you never wrote them. When you import a package such as express, TypeScript usually knows its functions too. Where does all this type information come from?

The answer is declaration files: files ending in .d.ts that contain only types. In this lesson you will learn what they are, the three places library types come from, how to use the huge DefinitelyTyped collection, and how to write a small declaration file yourself for a library that has none.

What is a declaration file?

A .d.ts file describes the shape of JavaScript code without containing any code itself. Think of it as a menu card: it lists every dish and its price, but no food. It uses the declare keyword, which means "this exists somewhere at run time; here is its type".

Imagine an old JavaScript file money.js in your project:

JavaScript
// money.js
export function toRupees(paise) {
  return "₹" + (paise / 100).toFixed(2);
}

export const GST_RATE = 0.18;

A matching money.d.ts next to it tells TypeScript the types:

TypeScript
// money.d.ts
export declare function toRupees(paise: number): string;
export declare const GST_RATE: number;

Now import { toRupees } from "./money.js" in a TypeScript file is fully typed. Function bodies and values are missing on purpose: the real code lives in money.js. When you compile a TypeScript library with the declaration option, tsc writes these .d.ts files for you, which is how library authors ship types.

Where library types come from

There are three sources, and TypeScript checks them automatically:

SourceExampleWhat you do
Built into TypeScriptlib.es2025.d.ts, lib.dom.d.tsChoose with target and lib in tsconfig.json
Bundled with the packagezod, axios, viteNothing: the package's package.json points to its .d.ts files
DefinitelyTyped@types/node, @types/express, @types/reactnpm install --save-dev @types/<name>

DefinitelyTyped is a large community project on GitHub that maintains type definitions for thousands of JavaScript packages that do not ship their own. Each one is published on npm under the @types scope:

Terminal
npm install --save-dev @types/node
npm install --save-dev @types/express

When you import express from "express", TypeScript finds node_modules/@types/express automatically. Packages that you only use as globals, such as Node.js's process or a test framework's describe, must also be listed in tsconfig.json, because TypeScript 7 loads no global @types packages unless you name them:

JSON
{
  "compilerOptions": {
    "types": ["node"]
  }
}

When there are no types

If a package has no types anywhere, importing it gives an error that explains the options:

Output
src/main.ts(1,22): error TS7016: Could not find a declaration file for module 'old-sms'. 'C:/projects/school-app/node_modules/old-sms/index.js' implicitly has an 'any' type.
  Try `npm i --save-dev @types/old-sms` if it exists or add a new declaration (.d.ts) file containing `declare module 'old-sms';`

The quick fix, declare module "old-sms"; in a .d.ts file, makes every import from that package any. That silences the error but turns off checking. A better fix is to describe the parts you actually use:

TypeScript
// src/types/old-sms.d.ts
declare module "old-sms" {
  export type DeliveryReport = { id: string; status: "sent" | "failed" };

  export function send(to: string, text: string): Promise<DeliveryReport>;
  export function balance(): Promise<number>;
}

Put the file anywhere inside the folders your tsconfig.json includes (a src/types folder is common). Now send is typed, autocomplete works, and a call such as send(9829012345, "Hi") is caught because the phone number must be a string. You only need to declare what you use; you can add more later.

Declaring globals

Some scripts create global variables, for example an analytics or payment script loaded with a <script> tag. TypeScript does not know about them. You can add them with declare global inside a module, or with plain declare statements in a script-style .d.ts file:

TypeScriptRun it yourself
export {}; // makes this file a module, required for "declare global"

declare global {
  var shopConfig: { city: string; currency: string; openHours: [number, number] };
}

// In a real page, a <script> tag would create this object before your code runs.
globalThis.shopConfig = { city: "Jaipur", currency: "INR", openHours: [10, 21] };

const [open, close] = shopConfig.openHours;
console.log(`${shopConfig.city} shop, prices in ${shopConfig.currency}`);
console.log(`Open ${open}:00 to ${close}:00`);
Output
Jaipur shop, prices in INR
Open 10:00 to 21:00

The declare global block produces no JavaScript at all; it only teaches TypeScript that shopConfig exists. Notice the use of var: global declarations need it, because only var creates a property on globalThis. This is one of the rare places where var is still correct.

Interfaces from libraries can be extended the same way through declaration merging (see Interfaces vs Type Aliases). For example, adding a property to the browser's Window interface:

TypeScript
declare global {
  interface Window {
    dataLayer: unknown[];
  }
}
export {};

Library types and skipLibCheck

.d.ts files from your dependencies are type-checked too, which takes time and can report errors in code you do not control. The skipLibCheck option, set by tsc --init, skips checking declaration files. It is safe for almost every project and makes builds faster.

Common mistakes

  • Writing code in a .d.ts file. Declaration files contain types only; a function body there is an error.
  • Using declare module "x"; forever. It makes everything any. Replace it with real declarations for the functions you use.
  • Installing @types for a package that ships types. Check the npm badge first.
  • Forgetting "types": ["node"] in TypeScript 7. Without it, process and Buffer are unknown even with @types/node installed.
  • Using let or const inside declare global for globals on globalThis. Use var.

Key points

  • A .d.ts declaration file contains only types and uses declare to describe code that exists elsewhere.
  • Types come from TypeScript's built-in lib files, from packages that bundle them, or from DefinitelyTyped's @types packages.
  • Imported packages find @types automatically; global ones must be listed in "types" in TypeScript 7.
  • Error TS7016 means a package has no types: install @types/<name> or write declare module "name" { ... }.
  • declare global adds global variables and extends interfaces such as Window; skipLibCheck speeds up builds.

Exercise

Your college project uses an old JavaScript package attendance-lib with two functions: markPresent(rollNo, date) returns true or false, and report(month) returns a promise of an array of { rollNo, daysPresent } objects. Write a declaration file for it, then write a TypeScript function that uses both functions with correct types.

Show solution
TypeScript
// src/types/attendance-lib.d.ts
declare module "attendance-lib" {
  export type MonthlyRow = { rollNo: number; daysPresent: number };

  export function markPresent(rollNo: number, date: string): boolean;
  export function report(month: number): Promise<MonthlyRow[]>;
}
TypeScript
// src/attendance.ts
import { markPresent, report, type MonthlyRow } from "attendance-lib";

export async function lowAttendance(month: number, minDays: number): Promise<MonthlyRow[]> {
  markPresent(14, "2026-10-30");
  const rows = await report(month);
  return rows.filter((row) => row.daysPresent < minDays);
}

The declaration file describes only what the project uses. Now report returns a typed promise, and a mistake such as markPresent("14", ...) is caught.

Quick Quiz

1. What does a .d.ts file contain?

2. Where are @types/... packages maintained?

3. In TypeScript 7, you installed @types/node but process is still unknown. Why?

4. What is the downside of declare module "old-sms"; with no body?

Learn TypeScript with a mentor

Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call