如何使用jsdom和typescript防止“属性'...'在'Global'类型上不存在”?
Posted
技术标签:
【中文标题】如何使用jsdom和typescript防止“属性\'...\'在\'Global\'类型上不存在”?【英文标题】:How to prevent "Property '...' does not exist on type 'Global'" with jsdom and typescript?如何使用jsdom和typescript防止“属性'...'在'Global'类型上不存在”? 【发布时间】:2017-04-06 04:52:56 【问题描述】:我尝试将现有项目转换为使用 Typescript,但我的测试设置出现问题。
我有一个用于设置 jsdom 的测试设置文件,以便我的所有 DOM 交互代码在我的测试期间都可以正常工作。使用 Typescript(带有 mocha 的 ts-node)我总是得到这样的错误:
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/');
【问题讨论】:
不能确定这是正确的答案,但是经历了类似的痛苦,事实证明你扩展 NodeJS.Global 接口的文件必须全小写,否则打字会忽略它.此外,它的顶部不能有任何导入或导出语句 - 否则它将被视为模块而不是类型文件。 这些答案似乎都不起作用,有人在 2018 年有答案吗? 【参考方案1】:避免错误的原始答案
把它放在你的打字稿文件的顶部
const globalAny:any = global;
然后使用 globalAny 代替。
globalAny.document = jsdom('');
globalAny.window = global.document.defaultView;
更新了维护类型安全的答案
如果您想保持您的类型安全,您可以扩充现有的 NodeJS.Global
类型定义。
您需要将您的定义放在全局范围内declare global ...
请记住,typescript global
范围与 NodeJS 接口 Global
或称为 global
类型 Global
的节点 global property
不同...
declare global
namespace NodeJS
interface Global
document: Document;
window: Window;
navigator: Navigator;
【讨论】:
通过转换any
来删除类型确实违背了首先使用 Typescript 的原因。事实上,如果你正在 linting TSLint 有一个选项可以专门防止这种情况发生:palantir.github.io/tslint/rules/no-any
@willsquire 我使用类型安全选项更新了解决方案。包括这对 OP 不起作用的主要原因。
此声明与不使用命名空间的 eslint 规则不兼容。看看我下面的答案,了解更有趣的方法。
问题与eslint无关,规则是个人风格问题。
ESLint 规则是个人的,真实的,但现在每个人通常都会使用所有默认规则作为基础,并禁用或修改这些他们不习惯的规则。我下面的解决方案涵盖了所有情况,IMO 它更具语义性,因此使答案更加完整。【参考方案2】:
declare namespace NodeJS
export interface Global window: any;
【讨论】:
纯代码答案对 SO 读者的教育作用很小。请编辑您的答案以包括一些解释。您的答案在审核队列中,因为它已被标记为低质量。 试过你的答案,但 global.window 仍未解决【参考方案3】:我通过这样做解决了这个问题...
export interface Global
document: Document;
window: Window;
declare var global: Global;
【讨论】:
export interface Global extends NodeJS.Global
如果您想修改一些但保留 Global 的其余属性,例如 fetch
【参考方案4】:
除了其他答案,你也可以直接在作业现场直接castglobal
:
(global as any).myvar = myvar;
【讨论】:
这与 typescript 的用法相矛盾,因为它是中立的类型检查,是 typescript 的第一个原则用法。 @ShahinGhasemi 真的,我到了一个我不在乎的地步。我已经厌倦了花费数小时甚至一整天来编译和运行我的应用程序。我曾经开发和生产,现在我花费越来越多的时间来解决打字错误、编译问题和依赖不兼容问题。我不在乎这是否违背了范式或违背了目的。在某个时候,我想要的只是我该死的应用程序编译并最终休息一下。这是唯一对我有用的解决方案。所有其他人只会导致新的错误和问题。【参考方案5】:避免类型转换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
【讨论】:
【参考方案6】:这是正确的解决方案,不使用 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-eslint 规则,eslint: error @typescript-eslint/no-unsafe-member-access - Unsafe member access .Global on an any value.
可能会弹出。通过之前添加type NJSGlobal = NodeJS.Global;
并扩展NJSGlobal
来解决。除此之外,这个解决方案似乎是最好的方法。
最干净的答案。人们应该支持这个。【参考方案7】:
一个简单的方法可以使用扩展Typescript“Window”类型
第 1 步:附加 Window 对象
interface Window
foo:string // any type of your foo property
第 2 步:声明
let foo = 'value of foo'
第三步:添加到窗口对象
window.foo
或
window.foo = foo
为我工作...
【讨论】:
以上是关于如何使用jsdom和typescript防止“属性'...'在'Global'类型上不存在”?的主要内容,如果未能解决你的问题,请参考以下文章
如何防止 jquery 使用 webpack 和 typescript 导入两次?
如何防止 Vetur 和 TypeScript 在 VSCode 中同时显示打字稿警告?