Extend the Node.js Global (globalThis) object in TypeScript

avatar

Borislav Hadzhiev

Thu Mar 10 20223 min read

banner

Photo by Nuno Antunes

Extend the Node.js Global (globalThis) object in TypeScript #

To extend the Global (globalThis) object 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 files 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 */ interface Employee { name: string; age: number; } declare global { var myObj: Employee; function sum(a: number, b: number): number; } export {};

The example above shows how to extend the global (globalThis) object with a property named myObj that is an object of type Employee and a sum 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 myObj: any; // 👈️ disables type checking for property function sum(a: number, b: number): number; } export {};

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

index.ts
global.myObj = { name: 'James', age: 30, }; console.log(global.myObj.name); // 👉️ "James" console.log(global.myObj.age); // 👉️ 30 global.sum = (a: number, b: number) => { return a + b; }; console.log(global.sum(50, 50)); // 👉️ 100

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 sum function and the myObj property accessible directly (globally) and on the global object.

index.ts
global.myObj = { name: 'James', age: 30, }; global.sum = (a: number, b: number) => { return a + b; }; console.log(global.myObj); // 👉️ {name: 'James', age: 30} console.log(global.sum(50, 50)); // 👉️ 100 console.log(myObj); // 👉️ {name: 'James', age: 30} console.log(sum(50, 50)); // 👉️ 100

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.

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

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

The provided file simply adds a myObj property with a type of any, which is most likely not what you need.

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.

TypeScript will merge the typings you declared on the global object with the original typings, so you will be able to access properties and methods from both declarations.

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