How to specify any newable type in TypeScript?
Asked Answered
L

3

9

I tried with this but it doesn't work. Foo is just a test of what works. Bar is the real try, it should receive any newable type but subclasses of Object isn't valid for that purpose.

class A {

}
class B {
    public Foo(newable: typeof A):void {

    }
    public Bar(newable: typeof Object):void {

    }
}

var b = new B();
b.Foo(A);
b.Bar(A); // <- error here
Loggerhead answered 19/10, 2015 at 21:14 Comment(0)
A
16

You can use { new(...args: any[]): any; } to allow any object with a constructor with any arguments.

class A {

}

class B {
    public Foo(newable: typeof A):void {

    }

    public Bar(newable: { new(...args: any[]): any; }):void {

    }
}

var b = new B();
b.Foo(A);
b.Bar(A);  // no error
b.Bar({}); // error
Alexandrina answered 19/10, 2015 at 21:50 Comment(0)
U
1

If you want to enforce only certain newables, you can specify the constructor's return type

interface Newable {
  errorConstructor: new(...args: any) => Error; // <- put here whatever Base Class you want
}

equivalent

declare class AnyError extends Error { // <- put here whatever Base Class you want
  // constructor(...args: any) // you can reuse or override Base Class' contructor signature
}

interface Newable {
  errorConstructor: typeof AnyError;
}

testing

class NotError {}
class MyError extends Error {}

const errorCreator1: Newable = {
  errorConstructor: NotError, // Type 'typeof NotError' is missing the following properties from type 'typeof AnyError': captureStackTrace, stackTraceLimitts
};

const errorCreator2: Newable = {
  errorConstructor: MyError, // OK
};
Unconsidered answered 31/10, 2019 at 13:7 Comment(1)
Note that this approach of AnyError extends Error is very specific to this case, because Error is not typed as Class in the internals and therefor cannot be simply used as typeof Error on the right side.Unconsidered
D
0

Using the Construct Signature feature of TypeScript, you can create a newable function.

/*
* Create a newable function
*/

type Vector2D = {
  x: number
  y: number
}

type Vector2DConstructor = {
  new(x: number, y: number): Vector2D
  (x:number, y: number): Vector2D
}

const Vector2D = function (this: Vector2D, x: number, y: number): Vector2D {
  if (x < 3) throw new Error('x cannot be smaller than 3')
  if (!new.target) {
    return {x, y}
  }
  this.x = x
  this.y = y
  return this
} as Vector2DConstructor // without type casting, it won't work

const a = new Vector2D(3, 3)
console.log(a)

You can try it on the playground.

There are some drawbacks to this:

  • You have to use type-cast, which is not safe for error checking.
  • You have to make sure the parameters of the Constructor type match the parameters of the function. Otherwise, it will create unexpected errors.
Doretha answered 25/12, 2022 at 8:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.