TypeScriptThe declare Keyword

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:

TS
// 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__)}`);
}
      

TS
// 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:

TS
// 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

TS
// 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:

TS
// 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';
  }
}
      
Note
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:

TS
// 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:

TS
// 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.

TS
// 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; // ✓
      
Warning
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 .ts files: Use declare for ambient declarations (globals, injected values). The rest of the file can have normal TypeScript.
  • In .d.ts files: Everything is ambient by default — you can omit the declare keyword on most declarations, though it is conventional to include it for clarity.

TS
// 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__);
}
      

TS
// 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

TS
// 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.