How to prevent "Property '...' does not exist on type 'Global'" with jsdom and typescript?

TypescriptJsdomtypescript2.0

Typescript Problem Overview


I try to convert an existing project to use Typescript and I have problems doing so with my testing setup.

I had a setup file for my tests that sets up jsdom so that all my DOM interacting code works during my tests. Using Typescript (ts-node with mocha) I always get errors like this:

Property 'window' does not exist on type 'Global'.

To prevent this I tried patching the NodeJS.Global interface like this:

declare namespace NodeJS{
  interface Global {
    document: Document;
    window: Window;
    navigator: Navigator;
  }
}

But this didn't change anything.

How do I enable those browser properties on the NodeJS global variable?

Extras:

This is my mocha setup.ts:

import { jsdom, changeURL } from 'jsdom';

const exposedProperties = ['window', 'navigator', 'document'];

global.document = jsdom('');
global.window = global.document.defaultView;
Object.keys(global.document.defaultView).forEach((property) => {
  if (typeof global[property] === 'undefined') {
    exposedProperties.push(property);
    global[property] = global.document.defaultView[property];
  }
});

global.navigator = {
  userAgent: 'node.js',
};

changeURL(global.window, 'http://example.com/');

Typescript Solutions


Solution 1 - Typescript

Original Answer To Avoid Error

Put this at the top of your typescript file

const globalAny:any = global;

Then use globalAny instead.

globalAny.document = jsdom('');
globalAny.window = global.document.defaultView;

Updated Answer To Maintain Type Safety

If you want to keep your type safety, you can augment the existing NodeJS.Global type definition.

You need to put your definition inside the global scope declare global {...}

Keep in mind that the typescript global scope is not the same as the NodeJS interface Global, or the node global property called global of type Global...

declare global {
  namespace NodeJS {
    interface Global {
       document: Document;
       window: Window;
       navigator: Navigator;
    } 
  }
}

Solution 2 - Typescript

In addition to other answers, you can also simply cast global directly at the assignment site:

(global as any).myvar = myvar;

Solution 3 - Typescript

I fixed this problem by doing this...

export interface Global {
  document: Document;
  window: Window;
}

declare var global: Global;

Solution 4 - Typescript

This is the right solution, not using Typescript's namespaces. It is also compatible with all eslint default rules:

// Declare a type.
interface CustomNodeJsGlobal extends NodeJS.Global {
    myExtraGlobalVariable: number;
    // You can declare anything you need.
}

Use it:

// Tell Typescript to use this type on the globally scoped `global` variable.
declare const global: CustomNodeJsGlobal;

function doSomething() {
  // Use it freely
  global.myExtraGlobalVariable = 5;
}

doSomething();

Solution 5 - Typescript

Avoid typecasting any, it removes the purpose of typings. Instead install the type definitions needed (e.g. yarn add --dev @types/jsdom @types/node) and import to use:

import { DOMWindow, JSDOM } from 'jsdom'

interface Global extends NodeJS.Global {
  window: DOMWindow,
  document: Document,
  navigator: {
    userAgent: string
  }
}

const globalNode: Global = {
  window: window,
  document: window.document,
  navigator: {
    userAgent: 'node.js',
  },
  ...global
}

Solution 6 - Typescript

declare namespace NodeJS {
  export interface Global { window: any;
  }
}

Solution 7 - Typescript

A simple method can be use extend the Typescript "Window" type

step 1: append Window object

interface Window {
    foo:string // any type of your foo property
}

step 2: declare

let foo = 'value of foo'

step 3: add to window object

window.foo 

or

window.foo = foo

work for me...

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
QuestionfahrradfluchtView Question on Stackoverflow
Solution 1 - TypescriptSteven SpunginView Answer on Stackoverflow
Solution 2 - TypescriptlleaffView Answer on Stackoverflow
Solution 3 - TypescriptShawnView Answer on Stackoverflow
Solution 4 - TypescriptJosé CaboView Answer on Stackoverflow
Solution 5 - TypescriptWill SquireView Answer on Stackoverflow
Solution 6 - TypescriptOleg MikhailenkoView Answer on Stackoverflow
Solution 7 - TypescriptAli VirkView Answer on Stackoverflow