Create a global variable in TypeScript

Typescript

Typescript Problem Overview


In JavaScript I can just do this:

 something = 'testing';

And then in another file:

 if (something === 'testing')

and it will have something be defined (as long as they were called in the correct order).

I can't seem to figure out how to do that in TypeScript.

This is what I have tried.

In a .d.ts file:

interface Window { something: string; }

Then in my main.ts file:

 window.something = 'testing';

then in another file:

 if (window.something  === 'testing')

And this works. But I want to be able to lose the window. part of it and just have my something be global. Is there a way to do that in TypeScript?

(In case someone is interested, I am really trying to setup my logging for my application. I want to be able to call log.Debug from any file without having to import and create objects.)

Typescript Solutions


Solution 1 - Typescript

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. Replace var with let or const won'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

Solution 2 - Typescript

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");

Solution 3 - Typescript

This is how I have fixed it:

Steps:

  1. Declared a global namespace, for e.g. custom.d.ts as below :
declare global {
    namespace NodeJS {
        interface Global {
            Config: {}
        }
    }
}
export default global;
  1. Map the above created a file into "tsconfig.json" as below:
"typeRoots": ["src/types/custom.d.ts" ]
  1. Get the above created global variable in any of the files as below:
console.log(global.config)

Note:

  1. typescript version: "3.0.1".

  2. In my case, the requirement was to set the global variable before boots up the application and the variable should access throughout the dependent objects so that we can get the required config properties.

Hope this helps!

Thank you

Solution 4 - Typescript

I found a way that works if I use JavaScript combined with TypeScript.

logging.d.ts:

declare var log: log4javascript.Logger;

log-declaration.js:

log = null;

initalize-app.ts

import './log-declaration.js';

// Call stuff to actually setup log.  
// Similar to this:
log = functionToSetupLog();

This puts it in the global scope and TypeScript knows about it. So I can use it in all my files.

NOTE: I think this only works because I have the allowJs TypeScript option set to true.

If someone posts an pure TypeScript solution, I will accept that.

Solution 5 - Typescript

The text posted here is a short version of the article TypeScript and Global Variables in Node.js

Since the release of TypeScript 3.4 there's a documented way to do it.

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 { };

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

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

To use the variables, just do something like:

import * as Logger from './logger';

// Initialize early
global.log = Logger;

// Use it
log.Info("Booting system...");

Enjoy :)

Solution 6 - Typescript

im using only this

import {globalVar} from "./globals";
declare let window:any;
window.globalVar = globalVar;

Solution 7 - Typescript

I spent couple hours to figure out proper way to do it. In my case I'm trying to define global "log" variable so the steps were:

  1. configure your tsconfig.json to include your defined types (src/types folder, node_modules - is up to you):
...other stuff...
"paths": {
  "*": ["node_modules/*", "src/types/*"]
}
  1. create file src/types/global.d.ts with following content (no imports! - this is important), feel free to change any to match your needs + use window interface instead of NodeJS if you are working with browser:
/**
 * IMPORTANT - do not use imports in this file!
 * It will break global definition.
 */
declare namespace NodeJS {
	export interface Global {
		log: any;
	}
}

declare var log: any;
  1. now you can finally use/implement log where its needed:
// in one file
global.log = someCoolLogger();
// in another file
log.info('hello world');
// or if its a variable
global.log = 'INFO'

Solution 8 - Typescript

Extend the other answer about globalThis (see MDN and TypeScript 3.4 note) with more specific examples (TypeScript only without mixing with JavaScript), as the behavior was fairly confusing. All examples are run under Nodejs v12.14.1 and TypeScript Version 4.2.3.

Simplest case with global scope

declare var ENVIRONMENT: string;
globalThis.ENVIRONMENT = 'PROD';
console.log(ENVIRONMENT);
console.log(globalThis.ENVIRONMENT);
// output
// PROD
// PROD

This file doesn't import or export so it's a global scope file. You can compile the above TypeScript code without any error. Note that you have to use var. Using let will throw error TS2339: Property 'ENVIRONMENT' does not exist on type 'typeof globalThis'.

You might notice that we declared the variable as opposed to the following which also works.

var ENVIRONMENT: string;
ENVIRONMENT = 'DEV';
globalThis.ENVIRONMENT = 'PROD';
console.log(ENVIRONMENT);
console.log(globalThis.ENVIRONMENT);
// output
// DEV
// PROD

The output is from Nodejs v12.14.1. I also tested it in Chrome (after compiling to JS) and both output PROD. So I'd suggest using globalThis all the time.

Simple case with module scope

declare var ENVIRONMENT: string;
globalThis.ENVIRONMENT = 'PROD';
export {};

Once we add export statement, it becomes a module scope file, which throws error TS7017: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature. The solution is to augment global scope.

declare global {
  var ENVIRONMENT: string;
}
globalThis.ENVIRONMENT = 'PROD';
console.log(globalThis.ENVIRONMENT);
export {};

You still have to use var, otherwise you will get error TS2339: Property 'ENVIRONMENT' does not exist on type 'typeof globalThis'..

Import for side effect

// ./main.ts
import './environment_prod';

console.log(ENVIRONMENT);
console.log(globalThis.ENVIRONMENT);
// ./environment_prod.ts
declare var ENVIRONMENT: string;
globalThis.ENVIRONMENT = 'PROD';

Or

// ./environment_prod.ts
declare global {
  var ENVIRONMENT: string;
}
globalThis.ENVIRONMENT = 'PROD';
export {}; // Makes the current file a module.

Browserify two files

Suppose both main.ts and environment_prod.ts are entry files. Browserify will wrap them (after compiled to JS) into local scoped functions which necessitates the use of globalThis.

// ./main.ts
declare var ENVIRONMENT: string;
console.log(ENVIRONMENT);
console.log(globalThis.ENVIRONMENT);

// ./environment_prod.ts
declare var ENVIRONMENT: string;
globalThis.ENVIRONMENT = 'PROD';

But it's more type-safe to share a declaration file which can then be imported by both entry files, to avoid typos of variable names or type names.

// ./main.ts
import './environment';

console.log(ENVIRONMENT);
console.log(globalThis.ENVIRONMENT);

// ./environment_prod.ts
import './environment';

globalThis.ENVIRONMENT = 'PROD';

// ./environment.ts
type Environment = 'PROD' | 'DEV' | 'LOCAL';

declare var ENVIRONMENT: Environment;

Note that the order matters: browserify environment_prod.js main.js > bin.js

Solution 9 - Typescript

Okay, so this is probably even uglier that what you did, but anyway...

but I do the same so...

What you can do to do it in pure TypeScript, is to use the eval function like so :

declare var something: string;
eval("something = 'testing';")

And later you'll be able to do

if (something === 'testing')

This is nothing more than a hack to force executing the instruction without TypeScript refusing to compile, and we declare var for TypeScript to compile the rest of the code.

Solution 10 - Typescript

I needed to make lodash global to use an existing .js file that I could not change, only require.

I found that this worked:

import * as lodash from 'lodash';

(global as any)._ = lodash;

Solution 11 - Typescript

This is working for me, as described in this thread:

declare let something: string;
something = 'foo';

Solution 12 - Typescript

It is work on browser
I found this in https://stackoverflow.com/a/12709880/15859431

declare global {
    interface Window {
        myGlobalFunction: myGlobalFunction
    }
}

Solution 13 - Typescript

As an addon to Dima V's answer this is what I did to make this work for me.

// First declare the window global outside the class

declare let window: any;

// Inside the required class method

let globVarName = window.globVarName;

Solution 14 - Typescript

This is how you create global variables for node app and typescript

File name is called typings/index.ts

declare global {
  var countSkipped: number;
  var countProcessed: number;
  var countLibUsedByFile: Record<string, number>;
}

export {};

If you happen to overrides a few prototypes, here's how you can add the typescript definition for the string prototype

declare global {
  interface String {
    blue(): string;
    yellow(): string;
    green(): string;
    red(): string;
  }
}

export {};

This is the sample prototype for the above string

String.prototype.blue = function () {
  return `\x1b[36m${this}\x1b[0m`;
};

String.prototype.yellow = function () {
  return `\x1b[33m${this}\x1b[0m`;
};

String.prototype.green = function () {
  return `\x1b[32m${this}\x1b[0m`;
};

String.prototype.red = function () {
  return `\x1b[31m${this}\x1b[0m`;
};

Solution 15 - Typescript

Also check out the answer here

// global.d.ts
export const thisIsAModule = true; // <-- definitely in a module

declare global {
    var foo: string;
}

Solution 16 - Typescript

I'm using this:

interface Window {
	globalthing: any;
}

declare var globalthing: any;

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionVaccanoView Question on Stackoverflow
Solution 1 - Typescriptedvard chenView Answer on Stackoverflow
Solution 2 - TypescriptBenoit B.View Answer on Stackoverflow
Solution 3 - TypescriptVikash Kumar ChoudharyView Answer on Stackoverflow
Solution 4 - TypescriptVaccanoView Answer on Stackoverflow
Solution 5 - TypescriptTomas NilssonView Answer on Stackoverflow
Solution 6 - TypescriptDima VView Answer on Stackoverflow
Solution 7 - TypescriptAlexeyView Answer on Stackoverflow
Solution 8 - TypescriptYuxuan XieView Answer on Stackoverflow
Solution 9 - TypescripttforgioneView Answer on Stackoverflow
Solution 10 - TypescriptTrueWillView Answer on Stackoverflow
Solution 11 - TypescriptNacho ColomaView Answer on Stackoverflow
Solution 12 - TypescriptXiao_e_yunView Answer on Stackoverflow
Solution 13 - TypescriptJonathan CardozView Answer on Stackoverflow
Solution 14 - TypescriptSy LeView Answer on Stackoverflow
Solution 15 - TypescriptfrancisView Answer on Stackoverflow
Solution 16 - TypescriptYehudaRView Answer on Stackoverflow