The declare Keyword
The declare keyword tells TypeScript: "This thing exists at runtime — trust me —
but don't emit any JavaScript for it." It is the foundational mechanism behind
all declaration files and ambient type definitions.
You use declare whenever TypeScript cannot see where a value comes from: a global
injected by the browser, a variable defined by a build tool, a class provided by
a JavaScript library, or a module whose implementation lives elsewhere.
declare vs Regular Declarations
Syntax | Emits JavaScript | Use case |
|---|---|---|
const x = 5 | Yes | Regular TypeScript code |
declare const x: number | No | Something that exists at runtime elsewhere |
function foo() {...} | Yes | Regular function definition |
declare function foo(): void | No | External function TypeScript should know about |
class Foo {...} | Yes | Regular class |
declare class Foo {...} | No | Class from a JS library |
declare const, let, var
Use declare const (or let/var) for global variables injected by your
environment, build tools, or browser:
// Build tools like webpack/Vite inject these at bundle time
declare const __DEV__: boolean;
declare const __VERSION__: string;
declare const __BUILD_TIMESTAMP__: number;
// Runtime environment checks
if (__DEV__) {
console.log(`Version ${__VERSION__} built at ${new Date(__BUILD_TIMESTAMP__)}`);
}
// Browser globals not in TypeScript's default lib
declare const grecaptcha: {
ready(callback: () => void): void;
execute(siteKey: string, options: { action: string }): Promise<string>;
};
declare const gtag: (command: string, ...args: unknown[]) => void;
// Usage — TypeScript now understands these
grecaptcha.ready(() => {
grecaptcha.execute('site_key', { action: 'submit' }).then(token => {
console.log(token); // string ✓
});
});
declare function
declare function describes a function that exists at runtime but is defined
outside TypeScript's view — typically in a CDN script or global environment:
// A utility function loaded via <script> in HTML
declare function formatCurrency(
amount: number,
currency: string,
locale?: string,
): string;
declare function debounce<T extends (...args: any[]) => any>(
fn: T,
delay: number,
): T;
// TypeScript checks calls to these functions normally
const price = formatCurrency(9.99, 'USD', 'en-US'); // string ✓
const debouncedSearch = debounce(search, 300); // same type as search ✓
declare class
// Typing a class from a legacy JavaScript library
declare class EventEmitter {
constructor();
on(event: string, listener: (...args: unknown[]) => void): this;
off(event: string, listener: (...args: unknown[]) => void): this;
emit(event: string, ...args: unknown[]): boolean;
once(event: string, listener: (...args: unknown[]) => void): this;
removeAllListeners(event?: string): this;
}
// TypeScript knows this class exists and checks usage
const emitter = new EventEmitter();
emitter.on('data', (chunk) => console.log(chunk));
emitter.emit('data', Buffer.from('hello'));
declare enum
declare enum describes an enum whose values are defined in external JavaScript.
It is purely a type-level construct and does not emit any JavaScript:
// Enum values come from a JavaScript library loaded separately
declare enum HttpStatus {
OK = 200,
Created = 201,
BadRequest = 400,
Unauthorized = 401,
NotFound = 404,
InternalServerError = 500,
}
function handleResponse(status: HttpStatus) {
if (status === HttpStatus.OK) {
return 'success';
}
if (status === HttpStatus.NotFound) {
return 'not found';
}
}
declare enum (ambient enum) differs from const enum. Ambient enums assume the values exist at runtime. Const enums are inlined by the compiler and have no runtime presence at all.declare namespace
declare namespace is used in declaration files to type global library objects —
the classic pattern for browser-global libraries (jQuery, lodash, etc.) and
most @types/* packages:
// Typing the jQuery global — simplified version of @types/jquery
declare namespace jQuery {
type Selector = string;
interface JQueryStatic {
(selector: Selector): JQuery;
(element: Element): JQuery;
ajax(url: string, settings?: AjaxSettings): JQueryXHR;
ready(handler: () => void): void;
}
interface JQuery {
addClass(className: string): this;
removeClass(className: string): this;
on(event: string, handler: (event: Event) => void): this;
find(selector: Selector): JQuery;
text(): string;
text(value: string): this;
}
interface AjaxSettings {
method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
data?: unknown;
success?: (data: unknown) => void;
error?: (error: unknown) => void;
}
interface JQueryXHR extends Promise<unknown> {}
}
declare const $: jQuery.JQueryStatic;
declare const jQuery: jQuery.JQueryStatic;
declare module
declare module gives TypeScript a type shape for a module it cannot resolve.
It is used inside .d.ts files to type untyped npm packages or non-JS imports:
// Typing an untyped npm package
declare module 'some-untyped-package' {
export interface Config {
apiKey: string;
timeout?: number;
}
export function initialize(config: Config): void;
export function getClient(): { fetch(url: string): Promise<unknown> };
export default class SomeClass {
constructor(config: Config);
doThing(): string;
}
}
// Asset imports (for bundler environments)
declare module '*.svg' {
const url: string;
export default url;
}
declare module '*.png' {
const url: string;
export default url;
}
declare global
Inside a module file (one that has import or export), use declare global
to add declarations to the global scope. Without it, declarations inside a module
are scoped to that module, not global.
// This file is a module (it has an export)
export {}; // makes this file a module
declare global {
// Extend the global Window type
interface Window {
myApp: {
version: string;
config: Record<string, unknown>;
};
}
// Add a global function
function trace(label: string, value: unknown): void;
// Add a global type
type Nullable<T> = T | null;
type Maybe<T> = T | null | undefined;
}
// Usage elsewhere — no import needed
window.myApp.version; // string ✓
const x: Nullable<string> = null; // ✓
declare global is only valid inside a module file (one with at least one import or export). In a script file (no imports/exports), declarations are already global — no wrapper needed.declare in .ts Files vs .d.ts Files
You can use declare in both regular .ts files and in .d.ts files:
- In
.tsfiles: Usedeclarefor ambient declarations (globals, injected values). The rest of the file can have normal TypeScript. - In
.d.tsfiles: Everything is ambient by default — you can omit thedeclarekeyword on most declarations, though it is conventional to include it for clarity.
// Inside a .ts file — mixed regular + ambient declarations
import { something } from './somewhere'; // regular import
// Ambient declaration for a runtime-injected global
declare const __SENTRY_DSN__: string;
// Regular TypeScript — both are valid in the same .ts file
export function initMonitoring() {
// __SENTRY_DSN__ exists at runtime (injected by build tool)
return new SentryClient(__SENTRY_DSN__);
}
// Inside a .d.ts file — everything is ambient
// The 'declare' keyword is conventional but often optional here
// These two are equivalent inside a .d.ts:
declare function foo(): void;
function foo(): void; // also ambient in .d.ts context
// But explicit 'declare' is preferred for clarity
declare abstract class
// Typing an abstract base class from a JavaScript framework
declare abstract class Component<Props = {}, State = {}> {
readonly props: Readonly<Props>;
state: Readonly<State>;
abstract render(): unknown;
setState(state: Partial<State>): void;
forceUpdate(): void;
componentDidMount?(): void;
componentDidUpdate?(prevProps: Props, prevState: State): void;
componentWillUnmount?(): void;
}
// Extend it in TypeScript
class MyComponent extends Component<{ name: string }, { count: number }> {
render() {
return `${this.props.name}: ${this.state.count}`;
}
}
Common declare Patterns Quick Reference
Pattern | Example | Use for |
|---|---|---|
declare const | declare const DEV: boolean | Build-time injected globals |
declare function | declare function fetch(...): Promise<Response> | External functions |
declare class | declare class Buffer {...} | Classes from JS libraries |
declare namespace | declare namespace React {...} | Global library objects |
declare module | declare module '*.css' {...} | Untyped packages, asset files |
declare global | declare global { interface Window {...} } | Extend globals from a module file |
declare enum | declare enum Status { OK = 200 } | Enums from external JS |
Summary
"declare" tells TypeScript a value exists at runtime without emitting any JavaScript.
Use declare const/let/var for globals injected by build tools or the environment.
Use declare function to describe external functions TypeScript cannot see.
Use declare namespace to type global library objects (jQuery, lodash-style UMD).
Use declare module to type untyped npm packages or non-JS asset imports.
Use declare global (inside a module file) to add declarations to the global scope.
In .d.ts files, declare is conventional but often implicit — everything is ambient.