63

I am trying to use globalThis in TypeScript and I would like some suggestions on how to write it in a better way.
Current implementation is like this:

Create a file types/global.d.ts and add inside

interface Global {
   foo: string
}

declare let foo: Global["foo"];

in tsconfig.json add

"files": [
  "types/global.d.ts"
]

Then in order to set the value of foo use

(globalThis as any).foo = "The value of foo"

What I don't like with this approach is first the boilerplate needed (but I think this cannot be avoided) and second the (globalThis as any).foo = expression

3
  • My first question would be the use of globalThis and if there is a solution available that doesn't require it. Can foo be referenced in a local scope or reduced scope rather than using a global object? Commented Dec 23, 2019 at 17:47
  • 1
    @AustinMehmet for this specific case the use of globalThis is needed. window object can still work for me. But the need for a global foo is required Commented Dec 23, 2019 at 17:55
  • No way to use any higher order wrappers to avoid globalThis either? Commented Dec 23, 2019 at 19:37

9 Answers 9

107

Update 2021 October

Applies to TypeScript 4.3+

Error

Element implicitly has an any type because type typeof globalThis has no index signature. ts(7017)

Solution

declare global {
  function myFunction(): boolean;
  var myVariable: number;
}

globalThis.myFunction = () => true;
globalThis.myVariable = 42;
  • IMPORTANT: This solution only works by declaring variables with var (do not use let or const).

Background

See the discussion on TypeScript issue 30139.

Traditionally, the way to specify a TypeScript declare-block in a Node.js context was as follows:

// Does not work as of October 2021 (TypeScript 4.3+)
declare global {
  module NodeJS {
    interface Global {
      myFunction(): boolean;
      myVariable: number;
    }
  }
}

tsconfig.json: noImplicitAny

Note that this error will be suppressed if the TypeScript setting noImplicitAny is set to false. It is recommended to enable noImplicitAny for better type checking.

Sign up to request clarification or add additional context in comments.

4 Comments

Wow! That var instead of let/const was a life-saver!
interesting, thanks!! but why only with var?
Can I extend an interface? I have a global type interface Window { myProp } so window.myProp works. Is there a way to make it work for gobalThis too, without typing everything twice?
27

My answer is based on the one by Edward Casanova. I was about to edit it, but there are still quite a few differences to the code that works for me, plus I can now give some additional information on this.

This is based on TypeScript 4.3.5

// typings/globals.d.ts (depending on your tsconfig.json)

export {}

interface Person {
  name: string
}

declare global {
  var someString: string
  var globalPerson: Person
}

This does not work without at least one export (or import) keyword. This turns this file into an ES module, which is necessary for this to work. You can export any of the statements or add an empty export {}.

The code above adds types for the following handles:

someString
window.someString
globalThis.someString

globalPerson.name
window.globalPerson.name
globalThis.globalPerson.name

On the other side, the following is possible, but the result is different:

export {}

declare global {
  let someLetString: string
  const someConstString: string
}

This only adds types for the following handles:

someLetString
someConstString

As expected, you cannot assign any value to someConstString. This might be useful for some older JS libraries that add the functionality to the global scope instead of exporting it. Libraries still can assign values to const in this case because it's just a type, not a real const. This const is only known to TypeScript code. But be aware that let and const don't add properties to the global objects window and globalThis. So, var might be the better choice here after all.

2 Comments

First answer that worked for me, thanks. Obviously you need to put export {} at the top. Duh. /s
This is super useful information that should be included in the official documentation. These differences are so nuanced, it gives people a sense of, "I swear this worked for me before!"
14

Using a combination of the other answers, here is what ended up working for me.

At the top of the TS file (or in a global typings file):

declare module globalThis {
    let myObj: { foo: string };
}
globalThis.myObj = { foo: 'bar' };

2 Comments

Thank you, this worked for me in TS 4.0.5 after all other answers didn't!
Declaration name conflicts with built-in global identifier 'globalThis'
4

You can use declaration merging in typescript to achieve this.

In your global.d.ts file:

export declare global {
  interface Window {
    // add you custom properties and methods
    foo: string
  }
}

Now you can use Window.foo without typescript warning you.

I wrote a mini blog about this on dev.to

8 Comments

Thank you for your answer. I get an error on declare global saying TS2669: Augmentations for the global scope can only be directly nested in external modules or ambient module declarations.
Edited to add export keyword at the start of line
I also have the global.d.ts file at the root of the project (same directory as tsconfig.json)
I don't know. Maybe I am missing something. Now I get TS2668: 'export' modifier cannot be applied to ambient modules and module augmentations since they are always visible.
what version of typescript you using? and what vertion of the typescript compiler: tsc --v or npx tsc --v
|
4

TypeScript 3.4 introduces support for type-checking ECMAScript’s new globalThis.

var x = 1
const y = 2
let z = 3
globalThis.x // ok
globalThis.y // should error, no property 'y'
globalThis.z // should error, no property 'z'
globalThis['x'] // ok
globalThis['y'] // should error, no property 'y'
globalThis['z'] // should error, no property 'z'
globalThis.Float64Array // ok
globalThis.Infinity // ok

declare let test1: (typeof globalThis)['x'] // ok
declare let test2: (typeof globalThis)['y'] // error
declare let test3: (typeof globalThis)['z'] // error
declare let themAll: keyof typeof globalThis

You can ready more about it in the documentation.

1 Comment

globalThis seems to be the future, but I haven't found a way yet on how to extend the globalThis with a typed property using TypeScript. I can do that for the Window interface and window object, but for globalThis I'm still searching for a solution.
4

This is what worked for me using typescript version 4.5.4,

  1. Create a new .d.ts file with the needed types:
export declare global {
    var foo: string;
    var goo: string;
}
  1. Add this file to tsconfig.json file (using files property)

Comments

3

I finally ended up with the following solution in global.d.ts

interface Window {
  foo: string
}

declare let foo: Window["foo"];

And used it in another file like

window.foo = "The value of foo"

2 Comments

any idea on how to use the same approach if you want to give the foo property a custom type? As custom types cannot be imported into the global.d.ts file I'm still looking for a solution to declare the extension of the Window/GlobalThis interface with a property of a custom complex type.
I don't really know about this issue. But could this stackoverflow.com/a/58375303/3414905 be a possible solution?
3

Found a way. Perhaps a decent workaround

In a "global.d.ts" file at the root of your project, write the following

declare global {    
    var [propertyYouWantToAdd]: any; or typeof "anything you want. Perhaps import a class from a module";

//Make sure you use var instead of let or const, as it attaches to the global object.     
}

Here's the reference in the docs

1 Comment

Actually, this is the only way that works for me (in TS 4.3) to make a property/variable known in the global context (without prefix), in window and globalThis at the same time. Just the example code is very confusing. You don't need brackets ([]). Also, any and typeof are very uncommon ways to declare a type. It should be something like var myVar: string;, or var myObj: SomeCustomInterfaceOrType;.
1

but if you find alternative to

window.foo = 'value of foo' 

then a simple solution is just

In typescript

other_var_name is the var holding other_var_value or an object or function

const foo = 'value of foo';
(global as any).foo;

work for me

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.