1. 程式人生 > >Typescript的宣告檔案如何對windows擴充套件

Typescript的宣告檔案如何對windows擴充套件

60

I setup global namespaces for my objects by explicitly setting a property on window.

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

TypeScript underlines MyNamespace and complains that:

The property 'MyNamespace' does not exist on value of type 'window' any"

I can make the code work by declaring MyNamespace

 as an ambient variable and dropping the window explicitness but I don't want to do that.

declare var MyNamespace: any;

MyNamespace = MyNamespace || {};

How can I keep window in there and make TypeScript happy?

As a side note I find it especially funny that TypeScript complains since it tells me that window

 is of type any which by definitely can contain anything.

asked Oct 3 '12 at 13:01

7,90993956

14 Answers

To keep it dynamic, just use:

(<any>window).MyNamespace

answered Jun 9 '15 at 19:18

3,0141107

  • 6

    Any ideas how to do this in a tsx file? – velop Mar 16 '17 at 7:06

  • 1

    I guess this only works without -noImplicitAny... – martin Apr 18 '17 at 19:16 

  • 1

    @martin: The <any> makes it explicit, so it works just fine, I believe. Others: If you are using Typescript with React or other JSX environment (resulting in TSX syntax) you'll have to use as instead of <>. See @david-boyd's answer below. – Don Aug 22 '17 at 15:59 

  • 6

    I had to use (window as any).MyNamespace – ArsalanDotMe Sep 19 '17 at 9:37

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

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

Basically you need to extend the existing window interface to tell it about your new property.

Luke

8,04923374

answered Oct 3 '12 at 13:46

7,90993956

  • 32

    does not work with the current version of typescript. – citykid Apr 1 '13 at 17:24

  • 4

    Note the capital W in Window. That tripped me up. – ajm Oct 9 '13 at 20:55

  • 2

    I couldn't get this to compile with tsc 1.0.1.0. Blake Mitchell's answer did work for me, though. – Pat Oct 13 '14 at 17:51

  • 33

    Be aware that this only works when declared in a separate .d.ts file. It does not work when used in a .ts file that uses imports and exports itself. See this answer. – cdauth Mar 9 '16 at 14:21

  • 10

    The declare global { interface Window { ... } } works with TypeScript 2.5.2, no need for .d.ts file as mentioned above – tanguy_k Sep 3 '17 at 20:29 

Or...

you can just type:

window['MyNamespace']

and you wont get a compile error and it works the same as typing window.MyNamespace

answered Nov 20 '12 at 19:36

8,02543557

  • 11

    but you will probably get a tslint error... If you have one of course – smnbbrv Jan 7 '16 at 12:34 

  • 34

    This completely flies in the face of strong typing, the whole idea behind TypeScript. – d512 Jan 28 '16 at 23:55

  • 5

    @user1334007 using globals does as well. However, some legacy code requires it. – nathancahill Mar 1 '16 at 17:03

  • @user1334007 this is the example when you need this stuff: andrewhfarmer.com/aws-sdk-with-webpack– SMSk Dec 5 '16 at 15:18

  • 2

    @Ramesh window['MyNamespace']() (just add brackets) – iBaff Dec 21 '17 at 18:14

Using TSX? None of the other answers were working for me. 

Here's what I did:

(window as any).MyNamespace

answered Aug 15 '16 at 23:25

3,94531513

  • 20

    It is the same except when using TSX, because the <any> gets interpreted as JSX, not a type cast. – Jake Boone May 15 '17 at 20:40

The accepted answer is what I used to use, but with TypeScript 0.9.* it no longer works. The new definition of the Window interface seems to completely replace the built-in definition, instead of augmenting it.

I have taken to doing this instead:

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

declare var window: MyWindow;

UPDATE: With TypeScript 0.9.5 the accepted answer is working again.

answered Aug 27 '13 at 21:22

1,76211619

  • 2

    This works also with modules as used by TypeScript 2.0.8. Example:  export default class MyClass{ foo(){ ... } ... }  interface MyWindow extends Window{ mc: MyClass }declare var window: MyWindow window.mc = new MyClass() Then you can call foo() e.g. from the Chrome Dev Tools console like  mc.foo() – Martin Majewski Dec 5 '16 at 16:43 

  • This is a very nice answer if you don't want to declare something as global. On the other side, you need to call declare var... in every file you need. – Puce May 25 at 12:23

If you need to extend the window object with a custom type that requires the use of import you can use the following method:

window.d.ts

import MyInterface from './MyInterface';

declare global {
    interface Window {
        propName: MyInterface
    }
}

answered Oct 23 '16 at 15:24

3,31133257

Global are "evil" :), i think the best way to have also the portability is:

First you export the interface: (eg: ./custom.window.ts)

export interface CustomWindow extends Window {
    customAttribute: any;
}

Second you import

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

Third cast global var window with CustomWindow

declare let window: CustomWindow;

In this way you don't have also red line in different IDE if you use with existent attributes of window object, so at the end try:

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

Tested with Typescript 2.4.x

5,06423656

answered Jul 27 '17 at 13:28

1,0201329

npm install typings --global

Create typings/custom/window.d.ts:

interface Window {
  MyNamespace: any;
}

declare var window: Window;

Install your custom typing: 

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

Done, use it‌! Typescript won't complain anymore:

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

answered Nov 19 '16 at 21:31

2,73862944

Most of the other answers are not perfect.

  • Some of them just suppress the type inference for shop.
  • Some of the others only cares about global variable as namespace, but not as interface/class

I also encounter the similar problem this morning. I tried so many "solutions" on SO, but none of them produce no type error absolutely and enable triggering type jumping in IDE(webstorm or vscode). 

Finally, from here

, I find a reasonable solution to attach typings for global variable which acts as interface/class and namespace both.

Example is below:

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

declare interface MyNamespace {
    somemethod?()
}

declare namespace MyNamespace {
    // ...
}

Now, the code above merges the typings of namespace MyNamespace and interface MyNamespaceinto the global variable myNamespace(the property of window).

answered May 19 '17 at 3:26

2,6111231

  • 1

    Thanks - this is the only one you can seemingly use in an ambient non-module context. – Tyler Sebastian Jul 26 '17 at 23:31

I don't need to do this very often, the only case I have had was when using Redux Devtools with middleware.

I simply did:

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

Or you could do:

let myWindow = window as any;

and then myWindow.myProp = 'my value';

answered Jun 6 at 13:13

31338

If you're using the Angular CLI it's really straightforward (tested on CLI RC.0):

src/polyfills.ts

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

my-custom-utils.ts

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

I'm using IntelliJ, so I also needed to change the following setting in the IDE before my new polyfills picked up:

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

answered Mar 21 '17 at 13:38

13.2k84342

For reference (this is the correct answer):

Inside a .d.ts definition file

type MyGlobalFunctionType = (name: string) => void

If you work in the browser, you add members to the browser's window context by reopening Window's interface:

interface Window {
  myGlobalFunction: MyGlobalFunctionType
}

Same idea for NodeJS:

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

Now you declare the root variable (that will actually live on window or global)

declare const myGlobalFunction: MyGlobalFunctionType;

Then in a regular .ts file, but imported as side-effect, you actually implement it:

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

And finally use it elsewhere in the codebase, with either:

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

myGlobalFunction("Kevin");

answered Apr 20 '17 at 15:50

2,0251314

After finding answers around, I think this page might be helpful.https://www.typescriptlang.org/docs/handbook/declaration-merging.html#global-augmentation Not sure about the history of declaration merging, but it explains why the following could work.

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

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

448417

answered Mar 16 '17 at 17:38

Sheng

12417

I wanted to use this in an Angular (6) library today and it took me a while to get this to work as expected. 

In order for my library to use declarations I had to use the d.ts extention for the file that declares the new properties of the global object. 

So in the end, the file ended up with something like:

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

Once created, don't forget to expose it in your public_api.ts.

That did it for me. Hope this helps.