How to add a static method to the built-in URL class?

1 day ago 2
ARTICLE AD BOX

I am trying to add a custom static method to the built-in global URL class in TypeScript so that I can do something like:

URL.create("/path", "https://example.com")

At runtime this is trivial:

(globalThis.URL as any).create = function ( url: string | URL, base?: string | URL ): URL { return new URL(url, base); };

The issue is getting this to work at compile time in a type-safe way. In lib.dom.d.ts, URL is declared like this:

declare var URL: { prototype: URL; new(url: string | URL, base?: string | URL): URL; canParse(url: string | URL, base?: string | URL): boolean; parse(url: string | URL, base?: string | URL): URL | null; createObjectURL(obj: Blob | MediaSource): string; revokeObjectURL(url: string): void; };

Notice that this is a:

var URL: { ... }

with an anonymous object type, so this prevents declaration merging such as:

declare global { interface URLConstructor { create(url: string | URL, base?: string | URL): URL; } }

because there is no URLConstructor in the standard library to merge with. As a result, I can't easily add static methods the same way we typically can with built-ins like Array, whose static side is declared via ArrayConstructor in the standard library and therefore supports declaration merging.

This also fails:

declare global { var URL: typeof URL & { create(url: string | URL, base?: string | URL): URL; }; }

since variable declarations don't merge the same way interfaces do.

Is there any type-safe way to augment the static side of the built-in global URL in TypeScript so that:

URL.create(...)

is both:

available at runtime; and properly typed at compile time;

without introducing a separate alias (like URLEx)?

Or is this fundamentally impossible because the DOM lib defines URL as a var with an anonymous type?

If this is by design, what is the recommended pattern for extending built-in globals with static methods?

Read Entire Article