circuit

TypeScript and Global Variables in Node.js

How to make global variables in Node.js using TypeScript and make sure the types are correct.




Photo by Blake Connally on Unsplash

Prerequisites: VSCode and TypeScript should be already installed.

TL;DR — Here is a working project: emptyts.

Declaring global variables

Create a file in the root of the project named global.d.ts with the following content. Please note:

  • The use of var , it's required for this to work (see typescriptlang.org for information about this).

  • Without the export {} , all variables will become any

    declare global {

      var Config: {
          Foo: string;
      };
    
      var Foo: string;
    

    }

    export {};

    ;

In the index.ts file, try to use the variables:

global.Config = { Foo: "Bar" };

global.Foo = "Bar";

Compiling with TypeScript

Make sure the tsconfig.json has proper sections for include and exclude . Example follows:

"include": [
    "src/**/*.ts",
  ],
  "exclude": [
    "node_modules",
    "<node_internals>/**",
    "bin/**"
  ]

Next, just compile (from the terminal). All should be OK.

tsc -b -v

Running from the terminal

node -r ts-node/register/transpile-only src\index.ts

Running in VSCode

Use this launch.json (or copy the configuration). Press F5 alternatively select and start the Debug typescript configuration by bringing up the command palette (ctrl-shift-p) and search for “Select and start debugging”.

{
 // Detailed docs:
 // [https://code.visualstudio.com/docs/nodejs/nodejs-debugging](https://code.visualstudio.com/docs/nodejs/nodejs-debugging)
 "version": "0.2.0",
 "configurations": [
  {
   "name": "Debug typescript",
   "type": "node",
   "request": "launch",
   "smartStep": false,
   "sourceMaps": true,
   "args": [
    "${workspaceRoot}/src/index.ts"
   ],
   "runtimeArgs": [
   "-r",
    "ts-node/register/transpile-only"
   ],
   "cwd": "${workspaceRoot}",
   "protocol": "inspector",
   "internalConsoleOptions": "openOnSessionStart",
   "env": {
    "TS_NODE_FILES": "true" // Respect include/exclude in tsconfig.json => will read declaration files  (ts-node --files src\index.ts)
   },
   "skipFiles": [
    "<node_internals>/*",
    "<node_internals>/**",
    "<node_internals>/**/*",
    "${workspaceRoot}/node_modules/**",
    "${workspaceRoot}/node_modules/**/*"
   ],
   "outputCapture": "std",
   "stopOnEntry": false
  }
 ]
}

Initializing global variables

In the following piece of code, we will set up a global logger and initialize it. Again, the variables must use var in order to work.

global.d.ts

type Logger = {
    Info: (iMessage: string) => void
}

declare global {
    var Foo: string;
    var log: Logger;
}

export { };

index.ts

index.ts initializes the global logger and then begins to use it.

Note that *initializing *the variable requires the use of global. (or globalThis. ), but using it doesn't. Example:

import * as Logger from './logger';
import * as expresshelper from './expresshelper'

**global.log **= Logger;

**log.Info**("Booting system...");
global.Foo = "Bar";
expresshelper.Init();
log.Info("Booting system Complete!");

export { }

logger.ts

The fantastic logger :)

console.log("logger is initializing...");

export function Info(iMessage: string) {
    console.log(`${new Date().toISOString()} Saving to log: ${iMessage}`);
}

expresshelper.ts

Note the // log.info , it will be discussed below.

// log.Info("Setting up Express");

export function Init() {
    log.Info("Initializing Express.")
}

Starting this code...

If you run this code, the following output will be rendered (as expected).

logger is initializing...
2021-08-14T08:51:25.620Z Saving to log: Booting system...
2021-08-14T08:51:25.621Z Saving to log: Initializing Express.
2021-08-14T08:51:25.621Z Saving to log: Booting system Complete!

Importing and code defined at the root of a file

What's important to understand is that import runs the code at the point of the file is read, so trying to uncomment the use of log.info in the expresshelper.ts file will give this error (since the global variable log is used before it has been initialized in index.ts ).

log.Info("Setting up Express");
^
ReferenceError: log is not defined

So, avoid code that uses global variables at the root of the files. Or avoid it altogether. :)

Modifying the global variables for another module

Example for Express follows:

global.d.ts

import "express";

declare global {
    namespace Express {
        interface Request {
            token: string,
            UserID: string
        }
    }
}

export { };

Enjoy!




Continue Learning