As of node@16 the NodeJS.Global interface has been removed in favor of globalThis.
You can declare new global variable in a module file as:
declare global {
var NEW_GLOBAL: string;
}
And in a non-module file (no top-level import/export) as:
declare var NEW_GLOBAL: string;
Important note: variable must be declared as var. let and const variables don't show up on globalThis.
As of node@16 the NodeJS.Global interface has been removed in favor of globalThis.
You can declare new global variable in a module file as:
declare global {
var NEW_GLOBAL: string;
}
And in a non-module file (no top-level import/export) as:
declare var NEW_GLOBAL: string;
Important note: variable must be declared as var. let and const variables don't show up on globalThis.
I saw this SO post and tried this:
You probably have something like vendor.d.ts:
// some import
// AND/OR some export
declare module NodeJS {
interface Global {
spotConfig: any
}
}
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.
More : https://basarat.gitbooks.io/typescript/content/docs/project/modules.html
Node.js global variable and TypeScript
Configure module files available in Node.js global scope
global variables in nodejs
You probably shouldn't be using a global variable for what you're trying to do, but…
to let TypeScript know about your own properties on the global object you need to augment the Global interface in a d.ts file:
export interface Global {
myProp: string;
}If all you want is to 'share' stuff across files (i.e. modules) you probably want to export from your modules rather than add to the global object.
More on reddit.comGlobal Variables
Videos
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.
- Assuming your source files live in a folder
src, create a new foldersrc/typesand create a fileglobal.d.tsin this folder. - 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;
}
}
- Make sure your
global.d.tsfile (and any other files you might add tosrc/types) is picked up by the TypeScript compiler, by adding the following to yourtsconfig.jsonfile:
{
"paths": {
"*": ["node_modules/*", "src/types/*"]
}
}
- Use the global variable as normal inside your code.
// Below, `app` will have the correct typings
const app = global.__EXPRESS_APP__;
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
}
I'm trying to add a global variable in nodejs but it doesn't find them in other files, I have 2 problems
-
Typescript doesn't let me use
global.varname, onlyglobal['varname']. -
How do I declare the variable in another file?
You probably shouldn't be using a global variable for what you're trying to do, but…
to let TypeScript know about your own properties on the global object you need to augment the Global interface in a d.ts file:
export interface Global {
myProp: string;
}
If all you want is to 'share' stuff across files (i.e. modules) you probably want to export from your modules rather than add to the global object.
The language spec has a lot to say about ambient declarations using the keyword 'declare' in section 1.1
I'm pretty sure 'declare var myThing' is what you are looking for. I could also be wrong.
Hey guys.
Lately, I've been messing around with TypeScript. I come from a full JS background and I wanted to upgrade myself to TS in my spare time.
For context, I've created numerous APIs using Express with JS and I wanted to see if I can recreate those APIs but this time in TS.
However, I've run into a problem: how do you create global variables in TypeScript?
In a NodeJS environment I would normally just go:
// index.js
global.foo = "and I call it a day"
// controller.js
global.foo = "Modified by a different file."
How do I replicate this behavior in TypeScript?
I'm not asking if I should be using Global Variables, or should I reinvent my existing architecture to not use Global Variables; I just need to know how to do it. I've tried endlessly Googling this and while I've come close to finding a solution none of them seem to fit the bill.
For example: http://marcinbiernat.pl/2020/03/nodejs-globals/
This guy just has him declaring things and it works perfectly. The problem I have with it is: I don't want the declarations to clog up index.ts for example. How do I separate my declarations from my code? Is that even possible?
The piece of code you shared is making use of global augmentation https://www.typescriptlang.org/docs/handbook/declaration-merging.html#global-augmentation
// Hint typescript that your global object will have a custom signin function
declare global {
function signin(): Promise<string[]>;
}
// Assign value to global.signin
global.signin = async () => { /* implementation */ };
Likely one or multiple modules ("mongoose", "supertest", "../app") imported by the test file is using global.signin (or window.signin) at some point (or maybe one of their nested imports is => look for "signin(" in the project). Thus for testing purposes, global.signin needed to be mocked. However just adding global.signin = something would raise a typescript error, because signin is not a standard global variable. This is where declare global comes into play. It hints typescript that in your particular context, a signin function is expected to exist in global scope.
JavaScript/TypeScript running in node will try to resolve anything it can't find in the current local scope in global (the same way a browser would look in window). Any function or variable you can access globally (e.g. setTimeout()), can also be accessed with global. as prefix. It just makes it explicit.
What happens in your code are two things:
declare global {
function signin(): Promise<string[]>;
}
Here it tells typescript's type system that the global object also has a function called signin. This part is not required but it makes sense required for typescript to allow you to access / define that function, in JavaScript you simply define it.
https://www.typescriptlang.org/docs/handbook/declaration-merging.html has some details how declare works.
global.signin = async () => {
// code ...
};
And here it is actually added to the global object.
In JavaScript non strict mode you could even write (notice the lack of var/let/const/global.)
signin = async () => {
// code ...
};
I don't see signin getting used anywhere in that code so the reason for it is unclear to me. As long as the file that defines it gets loaded you can call the function simply by referring to it as signin(). The global. is added implicitly.
The purpose of
declare global {
namespace Express {
interface Request {
currentUser?: UserPayload;
}
}
}
is more practical, in express you may want to add properties to your requests that get added by middleware. By declaring that the Express Request has a property called currentUser you get to do
app.get((req, res) => {
const user: UserPayload = req.currentUser
...
})
without typescript complaining about an unknown property. More on that for example https://blog.logrocket.com/extend-express-request-object-typescript/
to bundle global types, do the following. form typescript
- specify default typings directory at typeRoots. .e.g
"typeRoots": ["./src/types"]. - create a file
/src/types/global.d.tsin the specified directory - declare your types in the file inside
declare global {}and make sure to haveexport {}if you don't already export anything.
The short answer is:
TypeScript does not support Global types without importing the file referring to the type.
More details:
One example that I found doing this was Next.js - when creating a TypeScript app using npx create-next-app@latest --typescript you can start importing *.css files (for example) and get the correct type.
Where I got confused is that I originally thought that the type was coming from the next-env.d.ts but even when I deleted the file, *.css import was still working in Visual Studio code. But the reason it was, is because a file in the pages directory were importing Next.js' index.d.ts file.
Basically, in Visual Studio Code, as soon as your import a type somewhere in your project, if it's global, it will be accessible everywhere.
Workaround
So what can be done with the current TypeScript capabilities? To support new file types, you will need a file loader such as Webpack. The logical thing to do would be to add a reference to the file type declaration in the file loader itself. This way, as soon as you configure your file loader to be able to import the file, you will inherit the type:
- create a
txt.d.tsin our package's source directory (e.g.src) - you can use any name for the file, it's not important - if you are using eslint, add an entry to ignore the type file (e.g.
'src/*.d.ts'in yourignorePatternsoption - Since you are adding a
d.tsfile in your source that is not managed bytsc, you need to add a script that will perform the following actions:- Copy
txt.d.tsin the target directory of the compiled files for your package - Add this line at the top of your package's file loader (e.g.
loader/index.d.ts:/// <reference types="../txt" />\r\n- this will link the declaration file back into your package. Note that you can add this reference to any file of your package.
- Copy
This workaround will only work once you import the file referencing back to the declaration - this is the only way TypeScript can be made aware that this type exists (see https://github.com/microsoft/TypeScript/issues/49124).
Another alternative could also be to add manual steps (in a readme file) to add a global type declaration file.