Question
What does the declare keyword mean in TypeScript?
For example, what is the difference between these two declarations?
type Callback = (err: Error | string, data: Array<CalledBackData>) => void;
and
declare type Callback = (err: Error | string, data: Array<CalledBackData>) => void;
I could not find clear documentation explaining the purpose of declare in TypeScript. What does it do, and when should it be used?
Short Answer
By the end of this page, you will understand what declare means in TypeScript, why it is used for type-only information, and how it differs from normal declarations. You will also see where it appears in .d.ts files, when it is useful in real projects, and what mistakes beginners commonly make.
Concept
declare tells TypeScript:
- This thing exists somewhere else
- Use this information for type checking
- Do not generate JavaScript for it
TypeScript has two jobs:
- check types while you write code
- compile to JavaScript
Normally, when you write code, TypeScript may emit JavaScript output. But sometimes you want to describe something that already exists at runtime, such as:
- a global variable loaded by another script
- a function provided by a library
- types from an external JavaScript package
- browser or environment-specific globals
That is where declare is used.
For a type alias like this:
type Callback = (err: Error | string, data: Array<CalledBackData>) => void;
type already exists only in TypeScript's type system. It does not produce JavaScript anyway. So adding declare here usually does not change runtime behavior.
= ;
Mental Model
Think of declare as a label on a box you are not allowed to open.
TypeScript is told:
- "Trust me, this box exists"
- "Here is what is inside, at least from a typing point of view"
- "Do not try to build the box yourself"
Without declare, you usually provide the real thing:
const VERSION = "1.0.0";
With declare, you only describe it:
declare const VERSION: string;
So:
- normal declaration = description + implementation
- declare declaration = description only
For type, there is no runtime implementation anyway, so declare type is mostly about saying "this type is being declared for type purposes only," which is often redundant outside declaration-file contexts.
Syntax and Examples
The declare keyword can be used with several kinds of declarations.
Common syntax
declare const appName: string;
declare let currentUserId: number;
declare function fetchUser(id: number): Promise<string>;
declare class Logger {
log(message: string): void;
}
These tell TypeScript about values that exist somewhere else.
Example: external global variable
Imagine a script tag loads a library that creates a global variable named analytics.
declare const analytics: {
track(eventName: string): void;
};
analytics.track();
Step by Step Execution
Consider this example:
declare const API_URL: string;
function buildUrl(path: string) {
return API_URL + path;
}
const result = buildUrl("/users");
Here is what happens step by step:
-
TypeScript reads:
declare const API_URL: string;It records that a constant named
API_URLexists and that its type isstring. -
TypeScript does not expect an implementation here. There is no assigned value like:
const API_URL = "https://example.com"; -
In
buildUrl, TypeScript allows string concatenation becauseAPI_URLis known to be a string.
Real World Use Cases
declare is useful in several practical situations.
1. Typing global variables from external scripts
A script loaded in HTML might create a global:
declare const Stripe: {
init(key: string): void;
};
This lets your TypeScript code use Stripe safely.
2. Writing or consuming .d.ts files
Libraries often ship declaration files that describe their API:
declare function formatDate(date: Date): string;
This helps TypeScript users get autocomplete and type safety even if the library itself is plain JavaScript.
3. Gradually adding TypeScript to a JavaScript project
If runtime values already exist, you can declare them while migrating:
declare const legacyConfig: {
apiBase: ;
: ;
};
Real Codebase Usage
In real projects, developers usually use declare in these patterns.
Declaration files
The most common place is a .d.ts file:
declare module "legacy-lib" {
export function connect(url: string): void;
}
This tells TypeScript how to type a library.
Global augmentation
When a runtime global exists but TypeScript does not know about it:
declare global {
interface Window {
myAppVersion: string;
}
}
Then elsewhere:
console.log(window.myAppVersion);
Bridging JavaScript and TypeScript
During migration, teams often keep JavaScript implementations and add TypeScript declarations around them.
API surface description
Common Mistakes
1. Thinking declare creates a real variable
Broken expectation:
declare const apiKey: string;
console.log(apiKey);
This compiles, but if apiKey does not actually exist at runtime, your program will fail.
Avoid this by using declare only for values provided elsewhere.
2. Using declare when you should write a real implementation
Incorrect:
declare function add(a: number, b: number): number;
If you are implementing the function yourself, write:
function add(a: number, b: number): number {
a + b;
}
Comparisons
| Concept | Purpose | Exists at runtime? | Emits JavaScript? | Typical use |
|---|---|---|---|---|
type Callback = ... | Create a type alias | No | No | Reusable type definitions |
declare type Callback = ... | Declare a type alias in declaration-style context | No | No | Mostly .d.ts or generated typings |
const value = ... | Create a real value | Yes | Yes | Normal application code |
declare const value: ... | Describe a real value that exists elsewhere |
Cheat Sheet
// Type alias
type Callback = (err: Error | string, data: CalledBackData[]) => void;
// Declared value provided elsewhere
declare const API_URL: string;
// Declared function provided elsewhere
declare function fetchData(id: number): Promise<string>;
// Declared class provided elsewhere
declare class Client {
get(url: string): Promise<string>;
}
Key rules
declaremeans: this exists elsewhere; use it for type checkingdeclaredoes not create runtime codetypeandinterfaceare already type-only
FAQ
What does declare do in TypeScript?
It tells TypeScript that a variable, function, class, or other entity exists somewhere else and should be used only for type checking.
Does declare generate JavaScript code?
No. Declarations marked with declare are removed during compilation.
When should I use declare in TypeScript?
Use it when the real implementation is external, such as a global script, a JavaScript library, or a declaration file.
Is declare type necessary?
Usually no. A type alias is already type-only, so declare type is often redundant in regular .ts files.
What is an ambient declaration?
An ambient declaration is a declaration that describes something that exists at runtime but is defined elsewhere. declare is used for this.
Can declare cause runtime errors?
Yes. If you declare something that does not actually exist at runtime, TypeScript will be satisfied but JavaScript will fail.
Is declare mainly used in .d.ts files?
Mini Project
Description
Create a small TypeScript example that uses a declared global configuration object. This demonstrates the real purpose of declare: telling TypeScript about a runtime value that is provided elsewhere.
Goal
Build a function that reads from an externally provided config object using declare for type safety.
Requirements
- Declare a global configuration object with
apiBaseUrlandtimeoutproperties. - Write a function that builds a request URL from the config.
- Write a function that prints the timeout value.
- Show a mock runtime implementation for testing.
- Use TypeScript types correctly without redefining the config shape in multiple places.
Keep learning
Related questions
@Directive vs @Component in Angular: Differences, Use Cases, and When to Use Each
Learn the difference between @Directive and @Component in Angular, including use cases, examples, and when to choose each.
Angular (change) vs (ngModelChange): What’s the Difference?
Learn the difference between Angular (change) and (ngModelChange), when each fires, and which one to use in forms and inputs.
Angular @ViewChild Returning Undefined: Lifecycle, Child Components, and Fixes
Learn why Angular @ViewChild can be undefined, when it becomes available, and how to access child components correctly using lifecycle hooks.