Description
Summary
To support re-opening classes and built-ins as classes, I have proposed two suggestions (#2957, #2959) to help to better re-classify built-ins as class
declarations, rather than the current interface
-interface
-var
pattern we are using for built-in "classes". However, these changes would break existing projects that currently extend built-ins by re-opening the interfaces of these built-ins. This proposal seeks to support merging these declarations, so that existing code can continue to function.
Current State
Currently, authors can re-open the instance or static-side interface of many built-ins in lib.d.ts
to add new functionality. For example:
// lib.d.ts
interface Array<T> { /*... */ }
interface ArrayConstructor { /*...*/ }
declare var Array: ArrayConstructor;
// polyfill.ts
interface Array<T> {
includes(value: T): boolean;
}
interface ArrayConstructor {
of<T>(...items: T[]): T[];
}
Array.prototype.includes = function (value: any) { return this.indexOf(value) != -1; }
Array.of = function<T> (...items: T[]) { return items; }
The proposals in #2957 and #2959 would break existing libraries without some remediation method.
Proposal
I propose two steps to resolve this:
- Allow you to re-open the interface for the instance side of a class.
- Automatically generate a named interface for the static side of an ambient class declaration in the same lexical scope.
Re-open instance-side
Re-opening the instance-side of a class would be possible by merging interfaces with ambient class declarations in the same lexical scope:
// lib.d.ts
declare class Array<T> { /* ... */ }
// polyfill.ts
interface Array<T> {
include(value: T): boolean;
}
Automatic static-side interface
For backwards-compatibility, we could auto-generate a constructor interface for an ambient class declaration. As this is really intended to be a backwards-compatibility feature, we could opt to enable this only when we encounter a triple-slash directive. This would allow us to not only use this for our own lib.d.ts
, but also allow third parties to use this directive if need to migrate their existing declarations to support these new features.
// lib.d.ts
/// <reference auto-static-interface="true" />
declare class Array<T> { /* ... */ }
// Creates an `ArrayConstructor` symbol for the static interface of Array
// polyfill.ts
interface ArrayConstructor {
of(...args: T[]): T[];
}