Proposal: Merged Declarations for Classes and Interfaces #3332
Labels
Committed
The team has roadmapped this issue
Fixed
A PR has been merged for this issue
Suggestion
An idea for TypeScript
Milestone
Proposal for Merged Declarations between Classes & Interfaces
This is a proposal for a new feature, merging class/interface declarations, to allow existing libraries to remain type-compatible with dependencies that migrate from interface to class declarations as part of the process of updating to ES6.
Introduction
Consider lib1.ts and lib2.ts, where lib2.ts depends on and extends an interface in lib1.ts. Eg:
Today, through merged interface-interface declarations, lib2.ts can write the above code to extend the interface
Foo
. The prototypical example of this is in polyfill libraries, in particular those modifying standard built-in objects, such asArray<T>
. As part of the tsc compiler, we provide interface declarations forArray<T>
in src/lib/core.d.ts (ES3, ES5) and src/lib/es6.d.ts (ES6).To extend
Array<T>
, say with a proposed ES7 member function likeincludes()
(description available here), a library/polyfill creator might writeand then use the polyfilled
Array<T>
normally.With the advent of ES6, we would like to modify the API so that
Array<T>
is now declared aclass
instead of aninterface
. In ES6, built-in's can be subclassed, so the current API (with interface declarations) is difficult if not impossible to maintain while remaining consistent with ES6. Additionally, class-based declarations are cleaner. Since classes do not merge with interface declarations presently, this would present a breaking change to the API -- the above code would trigger an error. To allow for a more straightforward transition to ES6 declarations while retaining backwards compatibility, we propose merged declarations of ambient classes and interfaces.Details of Proposal
If an object is declared twice, once as an ambient class and then as an interface, then the resulting object is a class whose fields are both those of the class declaration and the interface declaration. The interface fields are marked public in the resulting type. On other words, the type of the class object is merged with the type of the interface. The class constructor object is unmodified.
Conflicts among the members/properties of the resulting type are resolved as if the object were declared contiguously within the class declaration.
The order of the declarations is irrelevant (ie: the behavior is the same regardless of whether the interface or class is declared first). Moreover A class can be merged with an arbitrary number of interfaces with the same name. For example,
resolves the type of Foo as
This proposal does not extend to allow merged declarations of classes-classes, classes-namespaces, or classes-functions. Moreover, since this applies only for the ambient portion class declarations, this proposal has no runtime behavior on the resulting type.
Pros
Foo
may want to polyfill a class. interface-class merged declarations allow for this facility (where the type is obtained from the library's corresponding .d.ts file).Cons
mergeable
or a compiler flag?Foo
is declared an interface, it is no longer a priori clear ifFoo
is actually an interface or a class or both. This may make some language service completion counter-intuitive.To Be Discussed
For the analogous code sample with merged declarations for interfaces, the type is resolved across both files, so both lines are okay. Do we want to emulate this behavior (ie: that the type is inferred globally for each usage)?
The text was updated successfully, but these errors were encountered: