Triple-slash directives
Declares compile-time dependencies on files, type packages or lib files from a comment at the top of a file.
/// <reference path="./other.d.ts" />
/// <reference types="node" />
/// <reference lib="es2017.string" />
/// <reference no-default-lib="true" />
/// <reference types="node" preserve="true" />
/// <amd-module name="NamedModule" />- Added in TypeScript 1.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$path | string | A path to another declaration or source file, resolved relative to the containing file. The referenced file is added to the compilation, and the reference contributes to output ordering under `--outFile`. |
$types | string | A package name, resolved the same way an import specifier is, declaring a dependency on that package's type declarations — `types="node"` pulls in `@types/node/index.d.ts`. |
$lib | string | A built-in library name as written in tsconfig's `lib` array, such as `es2017.string` or `dom` — not the `lib.*.d.ts` filename. |
$no-default-lib | "true" | Marks the file as a default library, excluding `lib.d.ts` from the compilation. Equivalent in effect to `--noLib` for files that include it. |
$preserveoptional | "true"= absent (directive is erased) | Keeps the directive in the emitted output. Since 5.5 handwritten directives are erased unless this is set. |
$nameoptional | string | On `/// <amd-module name="..." />`, the name given to the generated AMD module. |
Errors
Raises an error when a `path` reference points at a file that does not exist or at the file itself; `--noResolve` causes `path` references to be ignored entirely rather than resolved.
Changelog
- PHP 2.0`/// <reference types="..." />` added for declaring dependencies on type packages.
- PHP 3.0`/// <reference lib="..." />` added so declaration files can pull in built-in lib files without duplicating declarations.
- PHP 5.5Reference directives are no longer generated, and handwritten ones are erased from output unless marked `preserve="true"`.
A triple-slash directive is a single-line comment containing an XML tag, valid only at the very top of a file — before any statement, though other comments and directives may precede it. Placed anywhere else it is an ordinary comment and does nothing, silently.
When to reach for it
In modern projects, rarely. path references were how you ordered files before modules existed, and tsconfig.json's files, include and references replace them. Two uses remain genuinely current:
/// <reference types=".." />in a published.d.ts. If your declaration file mentionsBufferorprocess, this is how you declare a dependency on@types/nodeso consumers get it too. In your own.tsfiles, use tsconfig'stypesarray instead./// <reference lib=".." />when a declaration file uses an API from a newer lib than the consumer'stargetguarantees.
What trips people up
Since TypeScript 5.5, handwritten directives are erased from the emitted output unless you add preserve="true". If you ship a .d.ts that other packages depend on, that erasure breaks their build, and the failure surfaces in a consumer's project rather than yours.
Also: lib="es2015", not lib="lib.es2015.d.ts" — the value matches the tsconfig name, not the filename.
Example
/// <reference types="node" preserve="true" />
/// <reference lib="es2017.string" />
// Because of the lib reference, padStart type-checks even when
// tsconfig's target is older than ES2017.
const padded = "7".padStart(3, "0");
console.log(padded);
// -> "007"
// Because of the types reference, Node globals are in scope here
// without an import, and without listing "node" in tsconfig types.
console.log(typeof process.env === "object");
// -> trueWhen to use it
- Declare that a published .d.ts depends on @types/node so consumers pull it in
- Use a newer lib API such as String.prototype.padStart inside a declaration file
- Keep a legacy global-script codebase compiling before it is converted to modules
- Name an AMD module explicitly when emitting for a RequireJS-era loader
Frequently asked questions
Do I still need triple-slash directives in modern TypeScript?
Rarely. Use tsconfig's `include`, `files`, `types` and `references` for your own source. The directives that remain useful are `/// <reference types="..." />` inside a published `.d.ts`, to declare a dependency on a type package for your consumers, and `/// <reference lib="..." />` when a declaration file needs an API from a newer lib.
Why did my reference directive disappear from the output?
TypeScript 5.5 stopped emitting handwritten reference directives by default. Add `preserve="true"` — `/// <reference types="node" preserve="true" />` — to keep it in the generated file. This matters for packages whose published declarations rely on the directive reaching consumers.
What is the difference between reference types and reference path?
`types` names a package and resolves like an import specifier, declaring a dependency on that package's type declarations. `path` names a specific file relative to the current one and adds it to the compilation; it is the legacy mechanism for ordering global script files and has been superseded by module imports and tsconfig.
More examples
A published declaration file that depends on @types/node
`BufferEncoding` and `Buffer` are declared by @types/node, so a consumer whose tsconfig does not include "node" in `types` would otherwise see "Cannot find name 'Buffer'" inside your shipped declarations. The `preserve="true"` is what keeps the directive in the published file under TypeScript 5.5 and later — without it the line is stripped at emit and the dependency disappears.
// dist/index.d.ts (shipped in your package)
/// <reference types="node" preserve="true" />
export interface ReadOptions {
encoding?: BufferEncoding; // comes from @types/node
signal?: AbortSignal;
}
export declare function readAll(
path: string,
options?: ReadOptions
): Promise<Buffer>;
// consumer.ts — no reference needed here; the directive carried the dependency
import { readAll, type ReadOptions } from "my-package";
const opts: ReadOptions = { encoding: "utf8" };
console.log(Object.keys(opts));
// -> ["encoding"]The legacy path form, and what replaced it
The top half only works because neither file is a module: `Shape` and `Circle` live in the global scope and the directive tells the compiler the ordering for `--outFile`. The bottom half expresses the same dependency as a real import, which any bundler and any module target understands. If you still have `path` directives in a codebase, they are a marker of pre-module code, not something to add to new files.
// --- The old way: global scripts ordered by reference ---
// shapes.ts
interface Shape { area(): number }
// circle.ts
/// <reference path="./shapes.ts" />
class Circle implements Shape {
constructor(private r: number) {}
area(): number { return Math.PI * this.r ** 2; }
}
// --- The modern equivalent: modules, no directive ---
// shapes.ts
export interface Shape { area(): number }
// circle.ts
import type { Shape } from "./shapes.js";
export class Circle implements Shape {
constructor(private r: number) {}
area(): number { return Math.PI * this.r ** 2; }
}
console.log(new Circle(1).area().toFixed(4));
// -> "3.1416"
Discussion