如何用jsdom和typescript来防止"Property '...' does not exist on type 'Global'"?

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

我尝试将现有项目转换为使用 Typescript,但在我的测试设置中遇到问题。

我有一个用于设置 jsdom 的测试设置文件,以便我的所有 DOM 交互代码在我的测试期间都能正常工作。使用 Typescript(ts-node 和 mocha)我总是得到这样的错误:

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

为了防止这种情况,我尝试像这样修补 NodeJS.Global 接口:

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

但这并没有改变任何东西。

如何在 NodeJS 全局变量上启用这些浏览器属性?

额外:

这是我的摩卡 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/');

避免错误的原始答案

把它放在你的打字稿文件的顶部

const globalAny:any = global;

然后改用 globalAny。

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

维护类型安全的更新答案

如果您想保持类型安全,可以扩充现有的 NodeJS.Global 类型定义。

您需要将定义放在全局范围内declare global {...}

请记住,typescript global 作用域与 NodeJS 接口 Global 或节点 global property 调用 global 类型 [=16] 不同=]...

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

我通过这样做解决了这个问题...

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

declare var global: Global;

除了其他答案,你也可以直接在作业现场直接castglobal

(global as any).myvar = myvar;

避免类型转换 any,它消除了输入的目的。而是安装所需的类型定义(例如 yarn add --dev @types/jsdom @types/node)并导入以使用:

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
}

这是正确的解决方案,不使用 Typescript 的命名空间。它还兼容所有 eslint 默认规则:

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

使用它:

// 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();

可以使用一个简单的方法来扩展 Typescript“Window”类型

第 1 步:附加 Window 对象

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

第 2 步:声明

let foo = 'value of foo'

第 3 步:添加到 window 对象

window.foo 

window.foo = foo

为我工作...