A declaration file (.d.ts) holds only types, signatures without bodies, describing JavaScript the compiler cannot see, from lib.dom.d.ts (HTML DOM APIs) to a plain-JavaScript npm 2,036 package.
Writing, finding and publishing .d.ts files
Beside slugify.js, slugify.d.ts makes slugify(42) in a .ts file fail with error TS2345.
export interface SlugifyOptions {
/** Character placed between words. Default "-". */
separator?: string;
}
export declare function slugify(text: string, options?: SlugifyOptions): string;For packages that ship no types, install community ones such as npm install -D @types/lodash. DefinitelyTyped 51,442 (https://github.com/DefinitelyTyped/DefinitelyTyped 51,442 ) (51k stars) publishes them to the @types scope. Imported packages find their @types automatically, but global ones such as @types/node must be listed in "types", whose default became [] in TypeScript 6.0. New declarations start from the handbook's seven templates, or from npx dts-gen --dt --name <package> --template module:
| Library shape | Template | Key syntax |
|---|---|---|
| ES module | module.d.ts | export function |
| CommonJS class or function | module-class.d.ts, module-function.d.ts | export = |
| Globals from a script or module | global.d.ts, global-modifying-module.d.ts | declare namespace, declare global |
| Plugin for another library | module-plugin.d.ts, global-plugin.d.ts | Module augmentation |
To publish your own library's types, set "declaration": true, point "types" in package.json at the generated file and put the "types" condition first in "exports". npx @arethetypeswrong/cli --pack catches ESM/CommonJS type mismatches before release.
JSDoc for JavaScript projects
Keep .js files and still get checking: add // @ts-check (or "checkJs": true) and write types in JSDoc; @import (TypeScript 5.5) pulls types from other files.
// @ts-check
/** @typedef {{ name: string, price: number, qty: number }} CartItem */
/** @param {CartItem[]} items @param {number} [taxRate] */
export function total(items, taxRate = 0.08) {
const sum = items.reduce((acc, item) => acc + item.price * item.quantity, 0);
return Math.round(sum * (1 + taxRate) * 100) / 100;
}
total([{ name: "Pen", price: 2, qty: 3 }], "8%");src/cart.js(6,67): error TS2339: Property 'quantity' does not exist on type 'CartItem'. src/cart.js(9,44): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
tsc --allowJs --declaration --emitDeclarationOnly turns the comments into export declare function total(items: CartItem[], taxRate?: number): number;. The Svelte 36,701 compiler has been written this way since Svelte 4.