1

The bindNew incorrectly infers the constructor type, recognising only one of multiple overloaded version.

How it could be resolved?

function bindNew<C extends { new(...args: A): T }, A extends any[], T>(
  klass: C & { new(...args: A): T }
): C & ((...args: A) => T) {
  return new Proxy(klass, {
    apply(target, _self, args) { return new (target as any)(...args) }
  }) as any
}

class AClass {
  constructor(a: number)
  constructor(a: number, b: number)
  constructor(a: number, b?: number) {}
}

const A = bindNew(AClass)
A(0) // => Error: expects 2 arguments
A(0, 0)

// This works, but requires explicit type declaration
// interface A extends AClass {}
// const A = bindNew(AClass) as typeof AClass & {
//   (a: number): A
//   (a: number, b: number): A
// }

Playground

1
  • 1
    It's not currently possible in general; if you want something like this you'll need to write some fairly complicated type functions that tease apart the call/construct signatures from overloads, and then manipulates them. I'd say you should probably not try to do this if you don't have to. Class constructors being overloaded is probably the least useful approach because they always return a class instance, so you can just use unions-of-tuples as the answer below describes. Otherwise you want a feature TS doesn't currently have. Commented Dec 30, 2024 at 17:51

1 Answer 1

1

It seems it's impossible, TS infers the last overload signature. But you have a pretty simple case where you can just type the constructor's parameters as a union of tuples. I've changed the second signature to a: string so it would be clear that this signature is active in the second test case:

Playground

function bindNew<C extends { new(...args: A): T }, A extends any[], T>(
  klass: C & { new(...args: A): T }
): C & ((...args: A) => T) {
  return new Proxy(klass, {
    apply(target, _self, args) { return new (target as any)(...args) }
  }) as any
}

class AClass {
  constructor(...args: [a: number] | [a: string, b: number]){

  }
}

type t = ConstructorParameters<typeof AClass>

const A = bindNew(AClass)
A(0)
A('string', 0)
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.