如何在TypeScript中的`window`上显式设置新属性?

jos*_*hls 502 typescript

我通过显式设置属性来为我的对象设置全局命名空间window.

window.MyNamespace = window.MyNamespace || {};
Run Code Online (Sandbox Code Playgroud)

TypeScript强调MyNamespace并抱怨:

属性'MyNamespace'在'window'类型的值上不存在任何"

我可以通过声明MyNamespace为环境变量并删除window显式来使代码工作,但我不想这样做.

declare var MyNamespace: any;

MyNamespace = MyNamespace || {};
Run Code Online (Sandbox Code Playgroud)

我怎样才能window留在那里让TypeScript开心?

作为旁注,我发现TypeScript抱怨特别有趣,因为它告诉我这种window类型any绝对可以包含任何东西.

jos*_*hls 534

刚刚在另一个StackOverflow问题的答案中找到了答案.

declare global {
    interface Window { MyNamespace: any; }
}

window.MyNamespace = window.MyNamespace || {};
Run Code Online (Sandbox Code Playgroud)

基本上,您需要扩展现有window界面以告知它您的新属性.

  • 不适用于当前版本的打字稿. (54认同)
  • 请注意,这仅在单独的`.d.ts`文件中声明时才有效.在使用导入和导出本身的`.ts`文件中使用它时不起作用.见[这个答案](http://stackoverflow.com/a/30961346/242365). (39认同)
  • `declare global {interface Window {...}}`适用于TypeScript 2.5.2,不需要上面提到的`.d.ts`文件 (25认同)
  • `声明接口窗口{ __GLOBAL_VAR__:任何}` (9认同)
  • 注意窗口中的大写字母W. 那让我失望了. (6认同)
  • 我无法使用tsc 1.0.1.0进行编译.不过Blake Mitchell的回答对我有用. (2认同)
  • 最初,打字稿告诉我:“错误TS1234:仅在文件的顶层允许环境模块声明。”当我将其放在文件的顶部时,它确实解决了该错误,因此您可能必须这样做那也是。 (2认同)
  • 技巧:如果你把这些放在 index.d.ts 中,你必须添加一些导入(比如 `import * as React from 'react';`) (2认同)
  • 从TS 3.5.1开始,此方法再次起作用。 (2认同)
  • 如果您收到错误“TS2339:类型“Window & typeof globalThis”上不存在属性“MyNamespace”。” 然后在文件开头添加“export {}”。 (2认同)

chi*_*son 364

要保持动态,只需使用:

(<any>window).MyNamespace
Run Code Online (Sandbox Code Playgroud)

  • 我不得不使用(窗口为任何).MyNamespace (15认同)
  • 任何想法如何在tsx文件中执行此操作? (9认同)
  • @martin:&lt;any&gt; 使它明确,所以它工作得很好,我相信。其他:如果您在 React 或其他 JSX 环境中使用 Typescript(导致 TSX 语法),则必须使用 `as` 而不是 `&lt;&gt;`。请参阅@david-boyd 的[下面的答案](/sf/ask/889635211/#38964459)。 (3认同)
  • 我认为采用这种方法并不符合 TypeScript 的精神。当我在 TS 中编写项目时,我试图提高自己在用户之前发现错误的能力。这种方法只是使类型检查器保持沉默,但不能确保所定义的成员的正确使用。 (3认同)

Eva*_*sen 188

要么...

你可以输入:

window['MyNamespace']
Run Code Online (Sandbox Code Playgroud)

并且你不会得到编译错误,它的工作方式与键入相同 window.MyNamespace

  • 这完全违背了强类型,TypeScript背后的整个想法. (58认同)
  • 但你可能会得到一个tslint错误...如果你有一个当然 (14认同)
  • 使用globals的@ user1334007也是如此.但是,一些遗留代码需要它. (12认同)
  • 我真的必须回应@Auspex。TypeScript 不是你应该试图回避的东西。如果您正在使用 TS,请拥抱它并选择正确的类型。如果您不想这样做,请不要使用 TypeScript。如果您被迫使用它但又不想使用,请向您的经理提出放弃 TS 的理由,或者寻求帮助以正确输入。作为对强/静态类型的被动攻击性攻击,搞混和破坏 TS 代码库是极其不专业和任性的。 (6认同)
  • "这完全违背了强大的打字,TypeScript背后的整个想法."**好!** (4认同)
  • @Ramesh`window ['MyNamespace']()`(只需添加括号) (3认同)
  • @Cody 不,不好。如果你不想要强类型,就不要使用 TypeScript!为了绕过它的基本功能而对语言进行破坏是愚蠢的。 (3认同)
  • 在`^ 3.4.3`中不起作用。`TypeScript错误:元素隐式具有'any'类型,因为类型'Window'没有索引签名。TS7017` (2认同)

Dav*_*oyd 159

使用TSX?没有其他答案对我有用.

这是我做的:

(window as any).MyNamespace
Run Code Online (Sandbox Code Playgroud)

  • 除了使用TSX之外,它是相同的,因为`<any>`被解释为JSX,而不是类型转换. (35认同)
  • 有趣的是人们如何使用 Typescript 然后将其静音。这和根本不用它一样好。并认为这些答案是获得最多支持的答案!听起来很有希望... (7认同)
  • 与[`(<any> window).MyNamespace`](http://stackoverflow.com/a/30740935/4554883)相同 (2认同)
  • 窗口一样吗?那你为什么要使用打字稿呢?只需使用 JavaScript x) (2认同)

Bla*_*ell 63

接受的答案是我以前使用的,但使用TypeScript 0.9.*它不再有效.Window接口的新定义似乎完全取代了内置定义,而不是对其进行扩充.

我这样做了:

interface MyWindow extends Window {
    myFunction(): void;
}

declare var window: MyWindow;
Run Code Online (Sandbox Code Playgroud)

更新:使用TypeScript 0.9.5,接受的答案再次起作用.

  • 这也适用于TypeScript 2.0.8使用的模块.示例:`export default class MyClass {foo(){...} ...}``interface MyWindow extends Window {mc:MyClass}``declare var window:MyWindow``window.mc = new MyClass()`Then你可以调用foo(),例如从Chrome开发工具控制台调用,如`mc.foo()` (2认同)

ona*_*lbi 46

全球是"邪恶的":),我认为具有便携性的最佳方式是:

首先导出界面:(例如:./ custom.window.ts)

export interface CustomWindow extends Window {
    customAttribute: any;
}
Run Code Online (Sandbox Code Playgroud)

第二个你导入

import {CustomWindow} from './custom.window.ts';
Run Code Online (Sandbox Code Playgroud)

使用CustomWindow的第三个全局变量窗口

declare let window: CustomWindow;
Run Code Online (Sandbox Code Playgroud)

这样,如果你使用window对象的现有属性,你在不同的IDE中也没有红线,所以最后尝试:

window.customAttribute = 'works';
window.location.href = '/works';
Run Code Online (Sandbox Code Playgroud)

使用Typescript 2.4.x进行测试

  • 您可能想要扩展为什么全局变量是邪恶的。在我们的例子中,我们在 window 对象上使用了一个非标准化的 API。它现在是 polyfill 的。那真的是邪恶的吗? (3认同)
  • @onabi 我实际上是在谈论浏览器的一个功能。它是全球可用的,因为它是浏览器。您真的会建议采用全局定义仍然是错误的吗?我的意思是我们可以实现 Ponyfills,但这会使实际支持该功能的浏览器膨胀(例如全屏 api)。也就是说,我不相信所有的全局变量都是邪恶的。 (3认同)
  • @MathijsSegers 我不知道特别是你的情况,但是..关于全局变量是邪恶的不仅仅是关于 javascript.. 在每种语言中.. 一些原因是: - 你不能很好地应用设计模式 - 内存和性能问题(你让它们无处不在,尝试将一些东西附加到字符串对象,看看当你做新的字符串时会发生什么) - 名称冲突导致代码的副作用..(特别是在具有异步性质的 javascript 上)我可以继续,但我认为你可以想象休息... (2认同)
  • @MathijsSegers 在我看来,应该避免在我们可以的地方使用或修改全局变量.. 窗口是可用的,因为浏览器存在,但它一直在变化也是如此.. 所以如果例如我们现在定义window.feature = '功能'; 这在代码中大量使用.. 如果浏览器在所有代码上添加 window.feature 会发生什么情况,此功能将被覆盖.. 无论如何,我对我的句子的解释并不违背您.. 问候... (2认同)
  • 全局变量并不是“邪恶的”;而是“邪恶的”。这些东西有其一席之地,否则它们就会从编程语言中删除。有时全局变量确实是实现某些功能的最佳方式。邪恶的是“过度使用全局变量”。 (2认同)

Luc*_*Sam 43

如果需要window使用需要使用的自定义类型扩展对象,import可以使用以下方法:

window.d.ts

import MyInterface from './MyInterface';

declare global {
    interface Window {
        propName: MyInterface
    }
}
Run Code Online (Sandbox Code Playgroud)

请参阅手册的"声明合并"部分中的"全局扩充":https://www.typescriptlang.org/docs/handbook/declaration-merging.html#global-augmentation


小智 34

创建一个名为global.d.tseg的文件,/src/@types/global.d.ts然后定义一个接口,如:

interface Window {
  myLib: any
}
Run Code Online (Sandbox Code Playgroud)

参考:https : //www.typescriptlang.org/docs/handbook/declaration-files/templates/global-d-ts.html


Dim*_*ski 29

我不需要经常这样做,我唯一的情况是使用Redux Devtools和中间件.

我只是做了:

const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
Run Code Online (Sandbox Code Playgroud)

或者你可以这样做:

let myWindow = window as any;

然后 myWindow.myProp = 'my value';


Ste*_*aul 26

如果您使用的是Angular CLI,那么它非常简单:

SRC/polyfills.ts

declare global {
  interface Window {
    myCustomFn: () => void;
  }
}
Run Code Online (Sandbox Code Playgroud)

我定制,utils.ts

window.myCustomFn = function () {
  ...
};
Run Code Online (Sandbox Code Playgroud)

如果您正在使用IntelliJ,则还需要在新的polyfill拾取之前更改IDE中的以下设置:

> File 
> Settings 
> Languages & Frameworks 
> TypeScript 
> check 'Use TypeScript Service'.
Run Code Online (Sandbox Code Playgroud)

  • “声明全局”是诀窍,这个答案并不是真正特定于 Angular CLI... (3认同)

e-c*_*oud 18

大多数其他答案并不完美.

  • 其中一些只是抑制了商店的类型推断.
  • 其他一些只关心全局变量作为命名空间,而不是接口/类

今天早上我也遇到了类似的问题.我在SO上尝试了很多"解决方案",但它们都没有绝对产生类型错误,并且在IDE(webstorm或vscode)中启用触发类型跳转.

最后,从这里开始

https://github.com/Microsoft/TypeScript/issues/3180#issuecomment-102523512

,我找到一个合理的解决方案来为全局变量附加输入,它充当接口/类和命名空间.

示例如下:

// typings.d.ts
declare interface Window {
    myNamespace?: MyNamespace & typeof MyNamespace
}

declare interface MyNamespace {
    somemethod?()
}

declare namespace MyNamespace {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

现在,上面的代码将命名空间MyNamespace和接口的类型MyNamespace合并到全局变量myNamespace(窗口的属性)中.

  • 谢谢-这似乎是您可以在环境非模块环境中使用的唯一方法。 (2认同)

小智 16

// In typings.d.ts(is Global)
export declare global {
    interface Window {
        __PUBLIC__: string;
    }
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


小智 15

找到答案后,我认为这个页面可能会有所帮助. https://www.typescriptlang.org/docs/handbook/declaration-merging.html#global-augmentation 不确定声明合并的历史,但它解释了为什么以下方法可行.

declare global {
    interface Window { MyNamespace: any; }
}

window.MyNamespace = window.MyNamespace || {};
Run Code Online (Sandbox Code Playgroud)


Kri*_*ver 13

使用 create-react-app v3.3 我发现实现这一点的最简单方法是扩展Window自动生成的类型react-app-env.d.ts

interface Window {
    MyNamespace: any;
}
Run Code Online (Sandbox Code Playgroud)


Nik*_*iko 12

如果您使用的是TypeScript Definition Manager,请按照以下步骤操作!

npm install typings --global
Run Code Online (Sandbox Code Playgroud)

创建typings/custom/window.d.ts:

interface Window {
  MyNamespace: any;
}

declare var window: Window;
Run Code Online (Sandbox Code Playgroud)

安装自定义输入:

typings install file:typings/custom/window.d.ts --save --global
Run Code Online (Sandbox Code Playgroud)

完成,使用它!打字稿不会再抱怨了:

window.MyNamespace = window.MyNamespace || {};
Run Code Online (Sandbox Code Playgroud)

  • FWIW `typings` 已随 Typescript 2.0(2016 年中)过时,并已由所有者存档。 (3认同)

小智 11

[2022]:我们必须在 React 或 Nextjs 项目中扩展“window”对象。我们可以使用以下步骤来解决这个问题。

  • 在 src 文件夹名称中创建一个文件夹作为类型。

  • 在 types 文件夹内创建一个文件,名称为index.d.ts

  • 将此代码写入index.d.ts 文件中。 在此输入图像描述

    export {};
     declare global {
       interface Window {
        NameSpace: any;
       }
    
     }
     window.NameSpace= window.NameSpace|| {};
    
    Run Code Online (Sandbox Code Playgroud)

在此输入图像描述 保存此文件。

现在还有最后一项改变。

更改“ tsConfig.json ”文件。继承节点模块类型和我们的类型。

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

在此输入图像描述


Mas*_*iri 10

完整和简答

1- 将typeRoots属性添加到tsconfig.json

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

2-延伸Window

// file: src/@types/global.d.ts

declare global {
    interface Window { customProperty: <type>; }
}
Run Code Online (Sandbox Code Playgroud)


Ali*_*eza 9

使用

window["MyNamespace"] = window["MyNamespace"] || {};
Run Code Online (Sandbox Code Playgroud)

使用字符串属性应该没问题,但是如果你真的想要一个单独的窗口并组织你的代码,你可以扩展窗口对象:

interface MyNamespacedWindow extends Window {
    MyNamespace: object;
}

declare var window: MyNamespacedWindow;
Run Code Online (Sandbox Code Playgroud)


Mav*_*v55 7

首先,您需要在当前范围内声明 window 对象。
因为打字稿想知道对象的类型。
由于 window 对象是在其他地方定义的,因此您无法重新定义它。
但是您可以按如下方式声明它:-

declare var window: any;
Run Code Online (Sandbox Code Playgroud)

这不会重新定义 window 对象,也不会创建另一个具有 name 的变量window
这意味着 window 是在其他地方定义的,您只是在当前范围内引用它。

然后您可以简单地通过以下方式引用您的 MyNamespace 对象:-

window.MyNamespace
Run Code Online (Sandbox Code Playgroud)

或者您可以window简单地通过以下方式在对象上设置新属性:-

window.MyNamespace = MyObject
Run Code Online (Sandbox Code Playgroud)

现在打字稿不会抱怨了。


ken*_*0ki 7

从 3.4 版开始,TypeScript 已经支持globalThis. https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#type-checking-for-globalthis

  • 从上面的链接:
// in a global file:
var abc = 100;
// Refers to 'abc' from above.
globalThis.abc = 200;
window.abc = 300; // window object can also be used. 
Run Code Online (Sandbox Code Playgroud)

操场

“全局”文件是没有任何导入/导出语句的文件。所以声明var abc;可以写成.d.ts。

更新:添加了window对象和游乐场链接。

  • 确实如此。`lib.d.ts` 将 `window` 声明为 `Windows &amp; globalThis` 类型,这意味着这两种类型合并在一起。 (5认同)

Ben*_* B. 6

供参考(这是正确的答案):

.d.ts定义文件中

type MyGlobalFunctionType = (name: string) => void
Run Code Online (Sandbox Code Playgroud)

如果您在浏览器中工作,则可以通过重新打开Window的界面将成员添加到浏览器的window上下文中:

interface Window {
  myGlobalFunction: MyGlobalFunctionType
}
Run Code Online (Sandbox Code Playgroud)

NodeJS的想法相同:

declare module NodeJS {
  interface Global {
    myGlobalFunction: MyGlobalFunctionType
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,您声明根变量(实际上将存在于window或global上)

declare const myGlobalFunction: MyGlobalFunctionType;
Run Code Online (Sandbox Code Playgroud)

然后,在一个常规.ts文件中(但作为副作用导入),您实际上实现了它:

global/* or window */.myGlobalFunction = function (name: string) {
  console.log("Hey !", name);
};
Run Code Online (Sandbox Code Playgroud)

最后,通过以下任一方式在代码库中的其他地方使用它:

global/* or window */.myGlobalFunction("Kevin");

myGlobalFunction("Kevin");
Run Code Online (Sandbox Code Playgroud)


小智 6

创建一个自定义界面扩展Window并将您的自定义属性添加为可选属性。

然后,让customWindow使用自定义界面,但与原始窗口一起使用。

它与typescript@3.1.3一起使用。

interface ICustomWindow extends Window {
  MyNamespace?: any
}

const customWindow:ICustomWindow = window;

customWindow.MyNamespace = customWindow.MyNamespace {} 
Run Code Online (Sandbox Code Playgroud)


Dan*_*man 6

如果您使用的是Typescript 3.x,则可以declare global在其他答案中省略该部分,而只需使用:

interface Window {
  someValue: string
  another: boolean
}
Run Code Online (Sandbox Code Playgroud)

这在使用Typescript 3.3,WebPack和TSLint时与我合作。


Irs*_*had 6

打字稿不会对字符串属性执行类型检查。

window["newProperty"] = customObj;
Run Code Online (Sandbox Code Playgroud)

理想情况下,应避免使用全局变量方案。我有时用它来调试浏览器控制台中的对象。


aug*_*aug 5

对于那些想要在window对象上设置计算或动态属性的人,您会发现使用该declare global方法是不可能的。为了澄清此用例

window[DynamicObject.key] // Element implicitly has an 'any' type because type Window has no index signature
Run Code Online (Sandbox Code Playgroud)

您可能会尝试做这样的事情

declare global {
  interface Window {
    [DyanmicObject.key]: string; // error RIP
  }
}
Run Code Online (Sandbox Code Playgroud)

上面将错误。这是因为在Typescript中,接口不能很好地使用计算属性,并且会抛出类似

A computed property name in an interface must directly refer to a built-in symbol
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,你可以用暗示铸造去window<any>这样你就可以做

(window as any)[DynamicObject.key]
Run Code Online (Sandbox Code Playgroud)

  • 这就是2019年。 (2认同)

归档时间:

查看次数:

267805 次

最近记录:

5 年,10 月 前