// .d.ts files provide type info without runtime code
Note Declaration files describe the shape of existing JavaScript code. They contain only type information - no executable code. TypeScript automatically picks up .d.ts files in your project. Most npm packages include their own or have a @types/package companion.
// Tell TypeScript about a global that exists at runtimedeclareconst gtag:(
command:"config"|"event",
targetId: string,
params?:Record<string, unknown>)=>void;// Tell TypeScript about a global classdeclareclassStripe{constructor(apiKey: string);
charges:{create(params:{ amount: number; currency: string }):Promise<unknown>;};}gtag("event","purchase",{ value:99.99});
Output
// declare tells TypeScript 'trust me, this exists at runtime'
Note declare is for things that already exist in the runtime environment but TypeScript cannot see (global scripts, CDN libraries, injected variables). It emits zero JavaScript. Using declare when the value does not actually exist leads to runtime crashes with no compile-time warning.
// types/untyped-libs.d.ts// Type an entire untyped npm packagedeclaremodule"color-hash"{exportdefaultclassColorHash{constructor(options?:{ lightness: number });hex(input: string): string;rgb(input: string):[number, number, number];}}// Wildcard: type all .svg importsdeclaremodule"*.svg"{const content: string;exportdefault content;}// Wildcard: type all .css modulesdeclaremodule"*.module.css"{const classes:Record<string, string>;exportdefault classes;}
Output
// Now: import ColorHash from 'color-hash'; // fully typed
Note Ambient module declarations let you type third-party packages that lack types, or describe non-JS imports (CSS, SVG, images). Wildcard modules (*.ext) match any import path ending with that extension. Place these in a .d.ts file included in your tsconfig.
ambient moduledeclare moduletype untyped packagewildcard modulecss module typesvg import type
Module Augmentation
Syntax
// In a .ts file (not .d.ts)import"original-module";declaremodule"original-module"{interfaceExistingInterface{
newProperty:Type;}}
Example
// Augmenting Express Requestimport"express";declaremodule"express"{interfaceRequest{
userId?: string;
sessionToken?: string;
permissions?: string[];}}// Now in your middleware:import{Request,Response,NextFunction}from"express";functionauthMiddleware(req:Request, res:Response, next:NextFunction){
req.userId="usr_123";// No error - augmented
req.permissions=["read"];// No error - augmentednext();}
Output
// The augmented properties are available everywhere Request is used
Note Module augmentation extends existing module types without modifying the original package. The file performing augmentation must be a module itself (have at least one import/export). This only works for interfaces and namespaces - you cannot add new top-level exports through augmentation.
module augmentationextend module typesaugment expressadd property to typepatch types
/// <reference types="vite/client" />// Enables Vite-specific types like import.meta.env/// <reference lib="es2022" />// Includes ES2022 library types/// <reference path="./custom-globals.d.ts" />// Explicitly includes another declaration file
Output
// Triple-slash directives are special comments that instruct the compiler
Note Triple-slash directives must appear at the very top of the file (before any code). They are mostly obsolete for modern projects - tsconfig's 'types', 'lib', and 'include' options do the same job. The main surviving use case is /// <reference types="..." /> in .d.ts files and Vite/framework setups.
// LEGACY: Namespace (avoid in new code)namespaceValidation{exportinterfaceRule{validate(input: string): boolean;}exportclassEmailRuleimplementsRule{validate(input: string): boolean {return input.includes("@");}}}// MODERN: Use ES modules instead// validation.tsexportinterfaceRule{validate(input: string): boolean;}exportclassEmailRuleimplementsRule{validate(input: string): boolean {return input.includes("@");}}
Output
// ES modules are the standard; namespaces are legacy
Note Namespaces (formerly 'internal modules') are largely obsolete. Modern TypeScript projects should use ES modules (import/export) exclusively. Namespaces still appear in declaration files for global libraries and in legacy codebases. Do not use namespace and module imports in the same file.
namespacenamespace vs moduleinternal modulelegacy namespaceorganize types