如何使用jsdom和typescript防止'全局'类型中存在"属性'...'?

fah*_*cht 41 jsdom typescript typescript2.0

我尝试将现有项目转换为使用Typescript,我在测试设置时遇到了问题.

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

Property 'window' does not exist on type 'Global'.
Run Code Online (Sandbox Code Playgroud)

为了防止这种情况,我尝试修补NodeJS.Global接口,如下所示:

declare namespace NodeJS{
  interface Global {
    document: Document;
    window: Window;
    navigator: Navigator;
  }
}
Run Code Online (Sandbox Code Playgroud)

但这并没有改变任何事情.

如何在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/');
Run Code Online (Sandbox Code Playgroud)

Ste*_*gin 58

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

const globalAny:any = global;
Run Code Online (Sandbox Code Playgroud)

然后使用globalAny.

globalAny.document = jsdom('');
globalAny.window = global.document.defaultView;
Run Code Online (Sandbox Code Playgroud)

  • 通过强制转换'any`来删除typings真的违背了为什么要使用Typescript.事实上,如果你是linting TSLint有一个专门用于防止这种情况的选项:https://palantir.github.io/tslint/rules/no-any (7认同)
  • 此声明与不使用命名空间的 eslint 规则不兼容。请看我下面的回答,了解更有趣的方法。 (2认同)
  • ESLint 规则是个人的,确实如此,但现在每个人通常都会使用所有默认规则作为基础,并禁用或修改这些规则,而不是让他们感到不舒服。我下面的解决方案涵盖了所有情况,在我看来,它更具语义性,因此使答案更加完整。 (2认同)

lle*_*aff 23

除了其他答案,您还可以直接在分配站点投射 global:

(global as any).myvar = myvar;
Run Code Online (Sandbox Code Playgroud)

  • @ShahinGhasemi 真的,我已经到了我不在乎的地步。我厌倦了花费几个小时甚至一整天来编译和运行我的应用程序。我曾经负责开发和制作,现在我花越来越多的时间来解决打字错误、编译问题和依赖项不兼容问题。我不在乎这是否违背范式或违背目的。在某些时候我想要的只是我该死的应用程序编译并最终得到一些休息。这是唯一对我有用的解决方案。所有其他的只会导致新的错误和问题。 (5认同)
  • 这与打字稿的用法相矛盾,因为它是中立的类型检查,这是打字稿的首要原则用法。 (2认同)

小智 13

我这样解决了这个问题...

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

declare var global: Global;
Run Code Online (Sandbox Code Playgroud)

  • 如果要修改某些参数,但保留Global的其余属性,则可以使用export接口Global扩展NodeJS.Global,例如fetch。 (3认同)

wil*_*ire 8

避免 typecasting 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
}
Run Code Online (Sandbox Code Playgroud)


Jos*_*abo 8

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

// Declare a type.
interface CustomNodeJsGlobal extends NodeJS.Global {
    myExtraGlobalVariable: number;
    // You can declare anything you need.
}
Run Code Online (Sandbox Code Playgroud)

用它:

// 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();
Run Code Online (Sandbox Code Playgroud)


Gar*_*vae 5

如何声明某事global

\n
    \n
  1. 创建global声明文件,例如:src/types/index.d.ts
  2. \n
  3. 将您的global声明文件添加到tsconfig.json
  4. \n
\n
{\n  "compilerOptions": {\n    /* ... */\n    "typeRoots": [\n      "./src/types",\n    ],\n    /* ... */\n  },\n  /* ... */\n}\n
Run Code Online (Sandbox Code Playgroud)\n

来自打字稿文档

\n
\n

您可以从模块内部将声明添加到全局范围

\n
\n

因此,例如,如果您想向数组接口添加一些额外的内容,您需要执行以下操作:

\n

observable.ts(例子)

\n
{\n  "compilerOptions": {\n    /* ... */\n    "typeRoots": [\n      "./src/types",\n    ],\n    /* ... */\n  },\n  /* ... */\n}\n
Run Code Online (Sandbox Code Playgroud)\n

src/types/index.d.ts

\n
// observable.ts\nexport class Observable<T> {\n  // ... still no implementation ...\n}\n
Run Code Online (Sandbox Code Playgroud)\n

someWhereInApp.ts

\n
declare global {\n  interface Array<T> {\n    toObservable(): Observable<T>;\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

声明变量以从中访问它们global

\n

如果你想添加一个全局变量来用作global.myVariable您需要执行的操作:

\n

src/types/index.d.ts

\n
Array.prototype.toObservable = function () {\n  // ...\n};\n
Run Code Online (Sandbox Code Playgroud)\n

someWhereInApp.ts

\n
/* eslint-disable no-var */\ndeclare global {\n/*  \xe2\x86\x93\xe2\x86\x93\xe2\x86\x93 "var" is important  */  \n    var myVariable: string[];\n}\n/* eslint-enable no-var */\n
Run Code Online (Sandbox Code Playgroud)\n