Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggestion: allow instantiation of type aliases #2559

Open
zpdDG4gta8XKpMCd opened this issue Mar 31, 2015 · 11 comments
Open

Suggestion: allow instantiation of type aliases #2559

zpdDG4gta8XKpMCd opened this issue Mar 31, 2015 · 11 comments
Labels
Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. Suggestion An idea for TypeScript

Comments

@zpdDG4gta8XKpMCd
Copy link

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.

@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. labels Mar 31, 2015
@RyanCavanaugh
Copy link
Member

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?

@zpdDG4gta8XKpMCd
Copy link
Author

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>; }

@danquirk
Copy link
Member

Does #1616 cover this?

@zpdDG4gta8XKpMCd
Copy link
Author

@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

@danquirk
Copy link
Member

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.

@danquirk danquirk changed the title Suggestion: make type aliases as capable as the types they represent Suggestion: allow instantiation of type aliases Mar 31, 2015
@itsmontoya
Copy link

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

@zpdDG4gta8XKpMCd
Copy link
Author

zpdDG4gta8XKpMCd commented Aug 14, 2017

there is a workaround for classes
class MyClass<A, B, C> {}
class MyCertainClass extends MyClass<string, number, boolean> {}

@Ivanca
Copy link

Ivanca commented Dec 25, 2018

@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.

@russelldavis
Copy link
Contributor

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<number, number>; // 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<number, number> 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.

@kwasimensah
Copy link

I ran into this and just realized I could just replace

type Foos = Collection<Foo>;

with

class Foos extends Collection<Foo> {}

@wmertens
Copy link

wmertens commented Feb 4, 2022

adding a use case: type definition files.

When I want to declare a class that extends an imported class, I currently have to do this:

// Aclass is `class` but A is `type`
type A = import('./a-class').AClass

// @ts-ignore -- complains that A methods aren't implemented
declare class AC implements A {}

declare class B extends AC {
}

This seems to work but is ugly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Proposal This issue needs a plan that clarifies the finer details of how it could be implemented. Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

8 participants