Node.js global variable and TypeScript

20,088

Solution 1

Here's an approach. I don't know if this is the 'correct' way of doing things, but it works for me with TypeScript 3.7.4.

  1. Assuming your source files live in a folder src, create a new folder src/types and create a file global.d.ts in this folder.
  2. Author your declarations using one of the following strategies:
    • If you need to import external types into your declaration file, use the following syntax:
import { Express } from 'express';

declare global {
  namespace NodeJS {
    interface Global {
      __EXPRESS_APP__: Express;
    }
  }
}
  • If your declaration file does not contain any imports, the above will not work, and you'll need to use this syntax instead:
declare namespace NodeJS {
  interface Global {
    __CONNECTION_COUNT__: number;
  }
}
  1. Make sure your global.d.ts file (and any other files you might add to src/types) is picked up by the TypeScript compiler, by adding the following to your tsconfig.json file:
{
  "paths": {
    "*": ["node_modules/*", "src/types/*"]
  }
}
  1. Use the global variable as normal inside your code.
// Below, `app` will have the correct typings
const app = global.__EXPRESS_APP__;

Solution 2

I found this works.

Have one file that declares the property on the NodeJS.Global interface with the any type. This file has to be clean of imports or refrences.

node.d.ts

declare namespace NodeJS{
    interface Global {
        foo: any
    }
}

Then in the second file you declare a global variable that has the correct type.

global.d.ts

import IFoo from '../foo'

declare global {

  const foo:Ifoo

}
Share:
20,088
Alon
Author by

Alon

Updated on July 09, 2022

Comments

  • Alon
    Alon almost 2 years

    I need to have some strongly-typed global variables.

    As mentioned here: Extending TypeScript Global object in node.js, in order to add fields to the global variable I need to add a .d.ts file that extends the Global interface that's specified in node.d.ts.

    Also, as Basarat mentioned:

    Your file needs to be clean of any root level import or exports. That would turn the file into a module and disconnect it from the global type declaration namespace.

    Now, I need to have fields on the Global interface whose types are custom interfaces that I created:

    declare namespace NodeJS{
        interface Global {
            foo: Foo
            bar: Bar
        }
    }
    

    I'm extremely not willing to use the any type.

    I can move/copy all the interface declarations to this declaration file, but it's a bad solution for me, since both Foo and Bar in turn, aggregate many fields of other interfaces, including third party interfaces like Moment etc.

    I need a solution for this paradox

  • Jamie Birch
    Jamie Birch over 5 years
    Note that when using this method all global.foo usages will still, annoyingly, be of any type. However, you will at least be able to use foo as Ifoo type globally. Good enough to move forward, however. I wish the TypeScript team would comment on best practices for this; it's been an issue for as long as TypeScript has existed.
  • just coding
    just coding over 4 years
    i am getting this error TSError: ⨯ Unable to compile TypeScript: src/index.ts:3:8 - error TS2339: Property 'env' does not exist on type 'Global' while compiling
  • Kat Lim Ruiz
    Kat Lim Ruiz almost 4 years
    thiss really worked. The only solution I found that works. In my case, I only had primitive properties so in that case you only need node.d.ts global{ foo: string, bar: string } ...