How to extend the 'Window' typescript interface

26,086

Solution 1

You need the declare global

declare global {
  interface Window {
    fetch:(url: string, options?: {}) => Promise<any>
  }
}

This works then:

window.fetch('/blah').then(...); 

Solution 2

When you have a top-level import or export in your file (which you must somewhere to be having this problem), your file is an external module.

In an external module, declaring an interface always creates a new type rather than augmenting an existing global interface. This mimics the general behavior of module loaders -- that things declared in this file don't merge or interfere with things in the global scope.

The reason for this gyration is that otherwise there wouldn't be a way to, in an external module, define new variables or types with the same name as those in the global scope.

Share:
26,086
Ward
Author by

Ward

Updated on April 22, 2020

Comments

  • Ward
    Ward about 4 years

    In my example, I'm trying to extend the TS Window interface to include a polyfill for fetch. Why doesn't matter. The question is "how do I tell TS that window.fetch is a valid function?"

    I'm doing this in VS Code, v.0.3.0 which is running TS v.1.5 (IIRC).

    Declaring the interface inside my TS class file where I want to use it doesn't work:

    ///<reference path="typings/tsd.d.ts"/>
    
    interface Window {
      fetch:(url: string, options?: {}) => Promise<any>
    }
    ...
    window.fetch('/blah').then(...); // TS objects that window doesn't have fetch
    

    But it's OK if I declare this same interface in a separate ".d.ts" file and reference it in my TS class file.

    Here is "typings/window.extend.d.ts"

    ///<reference path="es6-promise/es6-promise"/>
    interface Window {
      fetch:(url: string, options?: {}) => Promise<any>
    }
    

    Now I can use it in my TS class file:

    ///<reference path="typings/window.extend.d.ts"/>
    ...
    window.fetch('/blah').then(...); // OK
    

    Alternatively, I can write an extending interface with another name in my TS class file and then use it in a cast:

    interface WindowX extends Window {
      fetch:(url: string, options?: {}) => Promise<any>
    }
    ...
    (<WindowX> window).fetch('/blah').then(...); // OK
    

    Why does extending the interface work in a "d.ts" but not in situ?

    Do I really have to go through these gyrations?

  • Stefan Hanke
    Stefan Hanke almost 9 years
    Can you provide a link to some documentation on this issue? Perhaps the Declaration Merging wiki entry needs to be extended?
  • Ward
    Ward almost 9 years
    I do have top-level import statements. What you say makes sense now that I understand. But I still don't know the pros/cons of the two approaches that worked or if there is a better 3rd way. I'm sure that extending window will be a common scenario that should be clearly documented. Declaration Merging surely needs elaboration ... especially since the interface Document example would not work in my use case!
  • BayOtter
    BayOtter almost 9 years
    We love typings when they are accurate. We loathe them when they are not. Having a clean path to extend them is important. Id like to know other options here too
  • Ryan Cavanaugh
    Ryan Cavanaugh almost 9 years
    The clean way is to put them in another file. There's not really another way to indicate that you want to declare something in the global namespace.
  • Sydwell
    Sydwell over 7 years
    For anyone using Angular 2 the interface definition goes in src\typings.d.ts and the actual assignment go anywhere else but most likely in src\app\shared\index.ts
  • Jeff Camera
    Jeff Camera over 7 years
    It is possible to extend the window object from within an external module. See my answer here: stackoverflow.com/a/40204572/274837
  • mayid
    mayid almost 7 years
    Are you using webpack? For me, the things I declare globally in one module are not visible in other modules. Any clue?
  • Andrew
    Andrew over 3 years
    The answer below helps clarify why this works. See also: typescriptlang.org/docs/handbook/…