question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Support for a built-in "constructable" type or "class type"

See original GitHub issue

TypeScript Version: 2.4.0

It would be interesting to allow type hinting for class type.

Something like

function generateMyClass(myClass: class) {
    return new myClass();
}

class Foo {}

generateMyClass(Foo); // Should work
generateMyClass('something else'); // should NOT work

Currently, the closest we have is

type Instantiable = {new(...args: any[]): any};

function doSomethingWithMyClass(myClass: Instantiable ) {
    // some code that doesn't matter
}

class Foo {}
abstract class Bar {}

doSomethingWithMyClass(Foo); // It works :)
doSomethingWithMyClass('something else' ); // It doesn't work and it's OK
doSomethingWithMyClass(Bar); // It doesn't work and it's NOT OK

It is of course logical that the abstract class causes an error with the code above, this is why it could be nice to have something to handle this case.

To go further, we can think about adding some genericity on it.

// With the actual implementation
type Instantiable<T = any> = {new(...args: any[]): T};
function foo<T>(myClass: Instantiable<T>): T { /* ... */ }

// With the new class type hint
function foo<T>(myClass: class<T>): T { /* ... */ }

Issue Analytics

  • State:open
  • Created 6 years ago
  • Reactions:44
  • Comments:13 (1 by maintainers)

github_iconTop GitHub Comments

8reactions
SamPrudencommented, Aug 3, 2017

We can actually get a little bit closer than this, but it’s still lacking.

type Abstract<T> = Function & {prototype: T};
type Constructor<T> = new (...args: any[]) => T;
type Class<T> = Abstract<T> | Constructor<T>;

This can work okay for some APIs, but also accepts functions, as their prototype has type any. The type is also not considered constructable, so we can’t extend from an object of type Class<T>.

I’ve actually just found another trick playing around with this now. I haven’t seen this anywhere before, I don’t know if this really works in the general case, would be nice to get some feedback.

abstract class EmptyAbstractClass {}
type Class<T = {}> = typeof EmptyAbstractClass & {prototype: T};

This seems to work nicely.

abstract class Foo {}
class Bar extends Foo {}
function foo<T>(C: Class<T>) {} // Accepts any class

foo(Foo); // Works as it should
foo(Bar); // Works as it should
foo(class{}); // Works as it should
foo(function(){}); // Fails as it should

And you can restrict the types of the class just fine.

abstract class Base { isBase = true; }
class Child extends Base {}
function bar<T extends Base>(C: Class<T>) {} // Accepts any class that extends Base

bar(Base); // Works as it should
bar(Child); // Works as it should
bar(class{}); // Fails as it should
bar(function(){}); // Fails as it should

Class<T> is considered a constructable type, so we can extend from it.

function makeDerived(C: Class<{}>) {
    return class extends C {};
}

However, this doesn’t quite seem to work generically. This complains that type 'makeDerivedGeneric<any>.(Anonymous class)' is not assignable to type 'T'. I’m not completely sure what’s going on here, or why TS can’t tell that the anonymous class type extends T. Adding generic constraints doesn’t seem to help.

function makeDerivedGeneric<T>(C: Class<T>) {
    return class extends C {}; // Error here
}

All this is in 2.4.2.

4reactions
maniwaicommented, Nov 30, 2020

TypeScript Version: 2.4.0

It would be interesting to allow type hinting for class type.

Something like

function generateMyClass(myClass: class) {
    return new myClass();
}

class Foo {}

generateMyClass(Foo); // Should work
generateMyClass('something else'); // should NOT work

Currently, the closest we have is

type Instantiable = {new(...args: any[]): any};

function doSomethingWithMyClass(myClass: Instantiable ) {
    // some code that doesn't matter
}

class Foo {}
abstract class Bar {}

doSomethingWithMyClass(Foo); // It works :)
doSomethingWithMyClass('something else' ); // It doesn't work and it's OK
doSomethingWithMyClass(Bar); // It doesn't work and it's NOT OK

It is of course logical that the abstract class causes an error with the code above, this is why it could be nice to have something to handle this case.

To go further, we can think about adding some genericity on it.

// With the actual implementation
type Instantiable<T = any> = {new(...args: any[]): T};
function foo<T>(myClass: Instantiable<T>): T { /* ... */ }

// With the new class type hint
function foo<T>(myClass: class<T>): T { /* ... */ }

Thank you for your post @noemi-salaun! Now I know I need to wait few years to come back to typescript. The workaround solutions below are awkward.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Documentation - TypeScript 2.2
A mixin constructor type refers to a type that has a single construct signature with a single rest argument of type any[] and...
Read more >
gcc - What is a `built-in type` - Stack Overflow
The malloc() and calloc() functions return a pointer to the allocated memory, which is suitably aligned for any built-in type. Now, GCC provides ......
Read more >
Classes - JavaScript - MDN Web Docs
Class body · Constructor · Static initialization blocks · Prototype methods · Generator methods · Static methods and fields · Binding this with ......
Read more >
TypeScript types you should know about - XP Bytes
Create a type from an object type without certain keys. The use-case is a safe(r) version than the built-in Omit , which doesn't...
Read more >
Announcing TypeScript 2.2 RC - Microsoft Developer Blogs
Meanwhile, the optional types that TypeScript adds can help you catch ... Timestamped<BC extends Constructable>(Base: BC) { return class ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found