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
Currently i'm using js-logger with babel-plugin-js-logger and @babel/plugin-transform-runtime, to make available a global logger function which can be invoked without any explicit imports. Rather we need to initialise the logger only once in the root module, say App.tsx, and it's automatically resolved at runtime by babel.
Currently when i use it in TypeScript, it's leading to linting as well as runtime errors.
This is the function that i use to initialise the logger in logger.ts:
import jsLogger from "js-logger";
const initializeLogger = () => {
jsLogger.useDefaults();
};
export default initializeLogger;
I invoke the above function once in App.tsx, within its useEffect. So I was thinking of adding a global function declaration for logger, such that TS is also able to understand what this function is all other files where i use say logger.info or logger.error etc.
I though adding the following to App.tsx would make this function available in all files.
import jsLogger from "js-logger"; declare var logger: typeof jsLogger;
But that doesn't seem to be working. Can anyone shed some light on this? What is the correct way to do this?
Node.js global variable and TypeScript
How to define global function in TypeScript? - Stack Overflow
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.comCreate a global variable in TypeScript - Stack Overflow
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
}
You're defining the type for the compiler, but not actually attaching it to the global namespace — window in the browser, global in node. Instead of exporting it from the module, attach it. For isomorphic use, use something like...
function s() { ... }
// must cast as any to set property on window
const _global = (window /* browser */ || global /* node */) as any
_global.s = s
You can also ditch the .d.ts file and declare the type in the same file using declare global, e.g.
// we must force tsc to interpret this file as a module, resolves
// "Augmentations for the global scope can only be directly nested in external modules or ambient module declarations."
// error
export {}
declare global {
function s<T>(someObject: T | null | undefined, defaultValue?: T | null | undefined) : T;
}
const _global = (window /* browser */ || global /* node */) as any
_global.s = function<T>(object: T | null | undefined, defaultValue: T | null = null) : T {
if (typeof object === 'undefined' || object === null)
return defaultValue as T;
else
return object;
}
Thanks to @Romain Deneau. His answer worked for me.
Here is my simplified one to make it look easier to get the point of his answer.
(Mine assumes the scripts run on a browser. Also, I omitted signature of function s.)
Define function outside of any class.
function s() {
console.log("invoked s()!");
}
(window as any).s = s;
Using this global function s from TypeScript class is like below;
declare var s;
export class MyClass {
public static callFunctionS() {
s();
}
}
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.
globalThis is the future.
First, TypeScript files have two kinds of scopes
global scope
If your file hasn't any import or export line, this file would be executed in global scope that all declaration in it are visible outside this file.
So we would create global variables like this:
// xx.d.ts
declare var age: number
// or
// xx.ts
// with or without declare keyword
var age: number
// other.ts
globalThis.age = 18 // no error
All magic come from
var. Replacevarwithletorconstwon't work.
module scope
If your file has any import or export line, this file would be executed within its own scope that we need to extend global by declaration-merging.
// xx[.d].ts
declare global {
var age: number;
}
// other.ts
globalThis.age = 18 // no error
You can see more about module in official docs
Inside a .d.ts definition file
type MyGlobalFunctionType = (name: string) => void
If you work in the browser, you add members to the browser's window context:
interface Window {
myGlobalFunction: MyGlobalFunctionType
}
Same idea for NodeJS:
declare module NodeJS {
interface Global {
myGlobalFunction: MyGlobalFunctionType
}
}
Now you declare the root variable (that will actually live on window or global)
declare const myGlobalFunction: MyGlobalFunctionType;
Then in a regular .ts file, but imported as side-effect, you actually implement it:
global/* or window */.myGlobalFunction = function (name: string) {
console.log("Hey !", name);
};
And finally use it elsewhere in the codebase, with either:
global/* or window */.myGlobalFunction("Kevin");
myGlobalFunction("Kevin");
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/
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?
I don't think what you're trying to achieve is doable without some sort of IoC that supports scoped lifecycles. Something like InversifyJS do support scoped lifecycles. I haven't used InversifyJS for Azure Functions before, though, and the samples I could find with my limited Google-foo skills seem experimental at best:
- mgomezarr's example on github
- jakkaj/Jordan Knight's take, also available on github
But the gist of it would be a service which is registered as scoped, and have a public property (either directly or via getter/setter methods) that can store your information (see inRequestScope for registering scoped services in InversifyJS).
Since the http trigger would be the root of the dependency graph in our case, and have the scoped service as dependency, any other dependencies we inject/resolve from our http trigger should share the same instance. Using the explanation on the about page for inRequestScope (the A -> B -> R, -> C -> R sample), "A" for us would be the HttpTrigger, and "R" would be the scoped service, "B" and/or "C" would be other services, like your user.service.ts.
I will note that this seems slightly excessive to implement, if all you want to achieve is to avoid having to parse values between methods (personal take). However, if your project is really large, and you have a lot of dependencies, and some of the values you have to parse around is for a dependency several layers deep, then I can understand why you want to avoid it.
I guess you can use the context.bindingData object to store and retrieve data within the context of the current function invocation. let me give you a modified code.
export async function users(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
const globalToken = validateToken(request);
// u can store the token in the context.bindingData for the current invocation
context.bindingData.globalToken = globalToken;
if (request.method === "GET") {
return { jsonBody: getUsers(context) };
}
}
export const getUsers = (context: InvocationContext) => {
// Retrieve the token from the context.bindingData
const globalToken = context.bindingData.globalToken;
// Use th token as wanted
return usersData.filter(u => u.userId === globalToken.userId);
};