How to declare Global Variables in TypeScript

avatar

Borislav Hadzhiev

Thu Mar 10 20224 min read

banner

Photo by Yoann Boyer

Declare Global Variables in TypeScript #

To declare a global variable in TypeScript, create a .d.ts file and use declare global{} to extend the global object with typings for the necessary properties or methods. TypeScript looks for .d.ts file in the same places it looks for your regular .ts files.

In your src directory, create a types directory that contains the following index.d.ts file:

src/types/index.d.ts
/* eslint-disable no-var */ declare global { var country: string; function multiply(a: number, b: number): number; } export {};

The example above shows how to extend the global object with a property named country that is a string and a multiply function.

Note that this will be different in your use case, so make sure to adjust the property names and the types.

Make sure to use the var keyword to add typings for properties you intend to set and use in other files.

You need to add the names and types of all of the properties you intend to access on the global object.

For example, if you don't know the type of the specific property and want to turn off type checking, set it to any.

src/types/index.d.ts
/* eslint-disable no-var */ declare global { var country: any; // 👈️ disables type checking for property function multiply(a: number, b: number): number; } export {};

Now, I'm able to set and access the specified property on the global object if using Node.js or on the window object if in the browser.

index.ts
global.country = 'Germany'; console.log(global.country); // 👉️ "Germany" // ✅ Can also be accessed directly console.log(country); // 👉️ "Germany" // 👇️ if you are in browser // console.log(window.country); global.multiply = function (a: number, b: number) { return a * b; }; console.log(global.multiply(16, 30)); // 👉️ 450 // ✅ Can also be accessed directly console.log(multiply(13, 10)); // 👉️ 130 // 👇️ if you are in browser // console.log(window.multiply(15, 15));

Note that you might still be getting an error in your terminal if you are using ts-node.

The problem is with ts-node not recognizing local declaration files.

To solve this, use the --files flag with your ts-node command, so instead of ts-node ./src/index.ts you should run ts-node --files ./src/index.ts.

I'm using nodemon with ts-node and here are the contents of my nodemon.json file.

nodemon.json
{ "watch": ["src"], "ext": ".ts,.js", "ignore": [], "exec": "ts-node --files ./src/index.ts" }

After adding the --files flag (only required if using ts-node), restart your server and you should be good to go.

Note that this makes the multiply function and the country property accessible directly (globally) and on the global (Node.js) or window (Browser) objects.

index.ts
global.country = 'Germany'; console.log(country); // 👉️ "Germany" global.multiply = function (a: number, b: number) { return a * b; }; console.log(multiply(13, 10)); // 👉️ 130

If you try to access a property that you haven't explicitly added in your declare global {} object, you'd get an error:

index.ts
// ⛔️ Error: Element implicitly has an 'any' // type because type 'typeof globalThis' // has no index signature.ts(7017) global.hello = 'world';

If you are still getting an error in your IDE, try adding the path to your types directory to your tsconfig.json file.

tsconfig.json
{ "compilerOptions": { // ... rest "typeRoots": ["./node_modules/@types", "./src/types"] } }

We used the export {} line in our index.d.ts file to mark it as an external module. A module is a file that contains at least 1 import or export statement. We are required to do that to be able to augment the global scope.

Note that you will have to change the contents of the provided index.d.ts file according to your use case.

TypeScript looks for .d.ts files in the same places it looks for your regular .ts files, which is determined by the include and exclude settings in your tsconfig.json file.

If you can't get this to work, you can try using a type assertion for a quick and dirty solution.

index.ts
// 👇️ or (global as any) if you are in Node.js (window as any).example = 'hello world'; console.log((window as any).example);

This approach should only be used when nothing else works as it is quite annoying to have to type the window or global object as any every time you need to access a property.

You might also use a more direct approach when declaring global variables.

Here is an example that doesn't use the declare global syntax, but instead declares

src/types/index.d.ts
/* eslint-disable no-var */ /** * IMPORTANT: 👇️ * file should not have imports or exports */ declare var country: string; declare function multiply(a: number, b: number): number;

The file directly declares a country and multiply global variables.

Note that the .d.ts file should not contain any imports or exports, otherwise you'd have to use the declare global{} syntax from the previous code snippets.

Now you are able to set and access the global variables in your code.

index.ts
global.country = 'Germany'; console.log(country); // 👉️ "Germany" // 👇️ if you are in browser // console.log(window.country); global.multiply = function (a: number, b: number) { return a * b; }; console.log(multiply(13, 10)); // 👉️ 130

Extending the Window interface in TypeScript #

If you need to extend the Window interface, use the declare global{} syntax in a .d.ts file.

src/types/index.d.ts
export {}; declare global { interface Window { myProperty: any; } }

The example above shows how to extend the Window interface with a property named myProperty that has a type of any.

Now, I'm able to set and access the specified property on the window object without getting any errors.

index.ts
window.myProperty = 'hello world'; console.log(window.myProperty);

If you try to access a property that you haven't added to the extended Window interface and does not exist on the original Window interface, you'd get an error:

index.ts
// ⛔️ Property 'example' does not exist on // type 'Window & typeof globalThis'.ts(2339) window.example = 'hello';

TypeScript will merge the declared from you Window interface with the original Window interface, so when you use the window object, you will be able to access properties from both interfaces.

Use the search field on my Home Page to filter through my more than 1,000 articles.