microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
101.33k stars 12.53k forks source link

URL interface is not part of the Window object #44245

Open Mereo4 opened 3 years ago

Mereo4 commented 3 years ago

Bug Report

As the title says, the URL interface (#3753) should be part of the Window object: window.URL. Please look at https://developer.mozilla.org/fr/docs/Web/API/URL .

🔎 Search Terms

window url, url, new url, createObjectURL, revokeObjectURL

🕗 Version & Regression Information

I'm using TypeScript 4.2.4.

🙁 Actual behavior

window.URL is not defined.

🙂 Expected behavior

window.URL should refer to the URL interface you added on the issue #3753:

URL: {
    prototype: URL;
    new(url: string, base?: string | URL): URL;
    createObjectURL(object: any): string;
    revokeObjectURL(url: string): void;
};
MartinJohns commented 3 years ago

But... It is?

https://www.typescriptlang.org/play?#code/HYUw7gBGCWwCYHswDoCqAlAMgCgEQAsAXQgBwGcAuAeioHNpD8BXAI2QGMEBbKr6dgE4IyCAGaEqAFQCeJEAGVB0EhNwBKANwBYAFBA

Mereo4 commented 3 years ago

Well, it's working in the Playground maybe because it's inferred, but not in an actual IDE (I'm using WebStorm). Here are the declarations in Typescript (lib.dom.d.ts):

interface URL {
    hash: string;
    host: string;
    hostname: string;
    href: string;
    toString(): string;
    readonly origin: string;
    password: string;
    pathname: string;
    port: string;
    protocol: string;
    search: string;
    readonly searchParams: URLSearchParams;
    username: string;
    toJSON(): string;
}

declare var URL: {
    prototype: URL;
    new(url: string, base?: string | URL): URL;
    createObjectURL(object: any): string;
    revokeObjectURL(url: string): void;
};

type webkitURL = URL;
declare var webkitURL: typeof URL;

The interface is declared as a standalone object, but not attached to Window. In my case, I can't directly use 'createObjectURL' and 'revokeObjectURL' through window.URL as this latter is not defined.

So I use some patch to make it work in the IDE, but it should be working without it:

export interface URLCompat {
  prototype: URL;
  new(url: string, base?: string | URL): URL;
  createObjectURL(object: any): string;
  revokeObjectURL(url: string): void;
}

export function provideWindowUrl(window: Window & { URL?: URLCompat }): URLCompat {
  if (!window.URL) {
    throw new Error('This application requires a recent browser in order to work.');
  }

  return window.URL;
}
fatcerberus commented 3 years ago

I gather this is what's being referred to:

type WindowURL = Window["URL"];  // Property 'URL' does not exist on type 'Window'
nmain commented 3 years ago

I think this is correct? URL isn't actually on Window in the webidl; it's there at runtime because window is also the global object. That's why typescript tracks window with type Window & typeof globalThis, and type Window['URL'] fails but type typeof window.URL succeeds.

Mereo4 commented 3 years ago

Ow, okay, sorry, I wasn't aware of globalThis and I didn't see this:

declare var window: Window & typeof globalThis

That's because I'm injecting the window object using Window type (as I don't want to use global instantiated objects in my code, to keep control on injections). But I'm lost... Is my way wrong? Shouldn't be static functions createObjectURL and revokeObjectURL available in actual Window type?

RyanCavanaugh commented 3 years ago

I'm not seeing a defect here and an actual code sample that isn't behaving the way you want would really be necessary to dig in further

Mereo4 commented 3 years ago

Well, hopefully this will be clear enough: Playground Link

As it seems I'm the only one who thinks this is a problem, if you still consider this is not, you may just close this issue, thanks.