- 
                Notifications
    You must be signed in to change notification settings 
- Fork 13.1k
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[];
}