Currently a type aliased class cannot be instantiated. Also there is no way to alias a type with type parameters. Please consider making type aliases as capable as the types that they represent, basically capturing the type expression under a different name.
We'd need some new type system machinery here. Consider something like this:
class Foo<T, U> {
constructor(public x: T, public y: U) { }
}
var f = Foo;
The type of f, from the type system's perspective, is this:
{
new<T, U>(x: T, y: U): { x: T; y: U; };
}
Note that this type _itself_ is not generic, so the expression Foo<number, string> in a value position (basically referring to typeof Foo<number, string>) has no meaning. We'd need some rule that says when you can and can't "push down" type parameters into construct signatures.
This is to say nothing of class-like things that have been modeled in .d.ts files as interface/var pairs instead of classes. What should this code do?
interface Foo<T, U> {
x: T;
y: U;
}
var Foo: {
new<S>(n: string): Foo<number, S>;
new<S, T>(n: number, m: string, z: any): Foo<T, U>;
new<S, T, U>(n: number): Foo<T, U>;
}
import q = Foo<number, number>; // Is this even legal? What does it mean?
var j = new q('hello'); // Valid?
Thanks, it's good to know. Clearly there is no straight way of doing it by the means TS currently has.
What should this code do?
import q = Foo<number, number>; // Legal. It means that q is { new (n: number, m: string, z: any): Foo<number, number>; }
var j = new q('hello'); // Invalid since q is { new (n: number, m: string, z: any): Foo<number, number>; }
Does #1616 cover this?
@danquirk it does if, besides being capable of type parameters, you add to it being capable of aliasing a class so that instantiating of such alias is possible
Yeah that's what I thought. I'll modify the title here to specifically reflect the instantiation aspect and we can use that issue to track the type parameters part since it already has a bunch of discussion and upvotes.
Is there any chance the proposal for this can be completed? This feature is really important in my honest opinion.
there is a workaround for classes
class MyClass {}
class MyCertainClass extends MyClass
@aleksey-bykov Is really weird object destructuring doesn't work with import aliases, meaning this works:
import {fabric} from 'fabric';
import Canvas = fabric.Canvas;
but this doesnt
import {fabric} from 'fabric';
import {Canvas} = fabric;
So you need to be too verbose if multiple aliases are needed because you need one line per alias.
Needs Proposal
Here's a proposal that should address this quite nicely.
We'd need some new type system machinery here
@RyanCavanaugh I'm guessing it didn't exist back when this written, but the machinery and semantics around subclassing do exactly what we want here. In particular:
import q = Foo
; // Is this even legal? What does it mean?
It would mean exactly what class q extends Foo<number, number> means, except the value of q would be equal to Foo rather than a subclass of it. In particular:
q is the return type from the constructor, and the constructor type of q is the same as Foo's, but with new overloads filtered based on the number of type parameters.I don't imagine that being too controversial, since it mirrors existing behavior. I think the only remaining question would be syntax.
Rather than extending import (which doesn't quite fit the semantics), I'd propose extending the class syntax, like this: class Foo = Bar<Baz>. This is backwards compatible, seems unlikely to conflict with future JS syntax, conveys the meaning well, and nicely mirrors the type syntax.
I ran into this and just realized I could just replace
type Foos = Collection<Foo>;
with
class Foos extends Collection<Foo> {}
Most helpful comment
Is there any chance the proposal for this can be completed? This feature is really important in my honest opinion.