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

时间:2012-10-03 13:01:16

标签: typescript

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

window.MyNamespace = window.MyNamespace || {};

TypeScript强调MyNamespace并抱怨:

  

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

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

declare var MyNamespace: any;

MyNamespace = MyNamespace || {};

如何将window保留在那里并使TypeScript满意?

作为旁注,我发现TypeScript抱怨特别有趣,因为它告诉我window类型为any,它绝对可以包含任何内容。

23 个答案:

答案 0 :(得分:410)

another StackOverflow question's answer中找到答案。

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

window.MyNamespace = window.MyNamespace || {};

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

答案 1 :(得分:337)

要保持动态,只需使用:

(<any>window).MyNamespace

答案 2 :(得分:169)

AS OF TYPESCRIPT ^ 3.4.3此解决方案不再起作用

或者...

你可以输入:

window['MyNamespace']

并且您不会收到编译错误,它与键入window.MyNamespace

的工作方式相同

答案 3 :(得分:58)

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

我已采取这样做:

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

declare var window: MyWindow;

更新:使用TypeScript 0.9.5,已接受的答案将重新开始。

答案 4 :(得分:38)

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

<强> window.d.ts

import MyInterface from './MyInterface';

declare global {
    interface Window {
        propName: MyInterface
    }
}

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

答案 5 :(得分:31)

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

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

export interface CustomWindow extends Window {
    customAttribute: any;
}

第二次导入

import {CustomWindow} from './custom.window.ts';

使用CustomWindow

创建第三个全局变量窗口
declare let window: CustomWindow;

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

window.customAttribute = 'works';
window.location.href = '/works';

使用Typescript 2.4.x进行测试

答案 6 :(得分:24)

我不需要经常这样做,我唯一的情况是将Redux Devtools与中间件一起使用。

我只是这样做了:

const composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

或者你可以这样做:

let myWindow = window as any;

然后myWindow.myProp = 'my value';

答案 7 :(得分:23)

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

interface Window {
  myLib: any
}

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

答案 8 :(得分:13)

如果你正在使用 Angular CLI ,那真的很简单:

的src / polyfills.ts

declare global {
  interface Window {
    myCustomFn: () => void;
  }
}

MY-定制utils.ts

window.myCustomFn = function () {
  ...
};

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

> File 
> Settings 
> Languages & Frameworks 
> TypeScript 
> check 'Use TypeScript Service'.

答案 9 :(得分:12)

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

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

今天早上我也遇到了类似的问题。我尝试了很多&#34;解决方案&#34;在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 {
    // ...
}

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

答案 10 :(得分:12)

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

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

window.MyNamespace = window.MyNamespace || {};

答案 11 :(得分:10)

如果您使用的是TypeScript Definition Manager

,请按照以下步骤进行操作
npm install typings --global

创建typings/custom/window.d.ts

interface Window {
  MyNamespace: any;
}

declare var window: Window;

安装自定义输入:

typings install file:typings/custom/window.d.ts --save --global

完成,使用它 Typescript不会再抱怨了:

window.MyNamespace = window.MyNamespace || {};

答案 12 :(得分:9)

使用create-react-app v3.3,我发现最简单的方法是在自动生成的Window中扩展react-app-env.d.ts类型:

interface Window {
    MyNamespace: any;
}

答案 13 :(得分:8)

使用

window["MyNamespace"] = window["MyNamespace"] || {};

使用字符串属性应该没问题,但是如果您确实希望有一个单独的窗口并组织代码,则可以扩展窗口对象:

interface MyNamespacedWindow extends Window {
    MyNamespace: object;
}

declare var window: MyNamespacedWindow;

答案 14 :(得分:5)

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

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

它与typescript@3.1.3。一起使用

interface ICustomWindow extends Window {
  MyNamespace?: any
}

const customWindow:ICustomWindow = window;

customWindow.MyNamespace = customWindow.MyNamespace {} 

答案 15 :(得分:4)

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

.d.ts定义文件

type MyGlobalFunctionType = (name: string) => void

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

interface Window {
  myGlobalFunction: MyGlobalFunctionType
}

NodeJS的相同想法:

declare module NodeJS {
  interface Global {
    myGlobalFunction: MyGlobalFunctionType
  }
}

现在声明根变量(实际上将存在于窗口或全局上)

declare const myGlobalFunction: MyGlobalFunctionType;

然后在常规.ts文件中,但作为副作用导入,实际上是实现它:

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

最后在代码库的其他地方使用它,使用:

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

myGlobalFunction("Kevin");

答案 16 :(得分:4)

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

interface Window {
  someValue: string
  another: boolean
}

在使用Typescript 3.3,WebPack和TSLint时,这与我一起工作。

答案 17 :(得分:4)

从 3.4 版开始,TypeScript 已经支持 globalThishttps://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;

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

答案 18 :(得分:2)

我今天想在Angular(6)库中使用它,我花了一些时间才能使它按预期工作。

为了使我的库使用声明,我必须对声明全局对象新属性的文件使用d.ts扩展名。

所以最后,文件最终显示为:

/path-to-angular-workspace/angular-workspace/projects/angular-library/src/globals.d.ts

创建后,请不要忘记将其暴露在您的public_api.ts中。

对我来说就做到了。希望这会有所帮助。

答案 19 :(得分:2)

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

window[DynamicObject.key] // Element implicitly has an 'any' type because type Window has no index signature

您可能会尝试执行类似的操作

declare global {
  interface Window {
    [DyanmicObject.key]: string; // error RIP
  }
}

以上内容将出错。这是因为在Typescript中,接口不能很好地发挥计算属性的作用,并且会引发类似

的错误
A computed property name in an interface must directly refer to a built-in symbol

要解决此问题,您可以建议将window强制转换为<any>,这样您就可以做到

(window as any)[DynamicObject.key]

答案 20 :(得分:2)

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

window["newProperty"] = customObj;

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

答案 21 :(得分:1)

typescript防止在不分配具有所需属性的类型的情况下访问对象,或者 已经分配给any,因此您可以使用可选的链接window?.MyNamespace = 'value'

答案 22 :(得分:0)

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

declare var window: any;

这不会重新定义窗口对象,也不会创建名称为window的另一个变量。
这意味着窗口是在其他地方定义的,您只是在当前作用域中引用它。

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

window.MyNamespace

现在打字稿也不会抱怨。