Typescript: Suggestion: allow instantiation of type aliases

Created on 31 Mar 2015  ·  10Comments  ·  Source: microsoft/TypeScript

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.

Needs Proposal Suggestion

Most helpful comment

Is there any chance the proposal for this can be completed? This feature is really important in my honest opinion.

All 10 comments

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:

  • If constructor overloads matching Foo have different return types, it's an error (ts2510)
  • Otherwise, the instance type of 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> {}
Was this page helpful?
0 / 5 - 0 ratings