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?
When you have a top-level
import
orexport
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.