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

Argument of type 'typeof FooBar' is not assignable to parameter of type 'new () => FooBarInterface' #2794

Closed
remojansen opened this issue Apr 16, 2015 · 3 comments

Comments

@remojansen
Copy link
Contributor

Hi guys I'm developing an IoC container for TypeScript apps called InversifyJS. I have implemented a class named TypeBinding<TServiceType> which is used to define a binding between a service type (interface) and a implementation type (class). The class code is the following:

// Defines allowed scope modes
enum TypeBindingScopeEnum {
  Transient,
  Singleton
}

class TypeBinding<TServiceType> {

    // The runtime identifier used because at runtime
    // we don't have interfaces
    public runtimeIdentifier : string;

    // The constructor of a class that must implement TServiceType
    public implementationType : { new(): TServiceType ;};

    // Cache used to allow singleton scope
    public cache : TServiceType;

    // The scope mode to be used
    public scope : TypeBindingScopeEnum;

    constructor(
      runtimeIdentifier : string,
      implementationType : { new(): TServiceType ;},
      scopeType? : TypeBindingScopeEnum) {

      this.runtimeIdentifier = runtimeIdentifier;
      this.implementationType = implementationType;
      this.cache = null;
      if(typeof scopeType === "undefined") {
        // Default scope is Transient
        this.scope = TypeBindingScopeEnum.Transient;
      }
      else {
        if(TypeBindingScopeEnum[scopeType]) {
            this.scope = scopeType;
        }
        else {
          var msg = `Invalid scope type ${scopeType}`;
          throw new Error(msg);
        }
      }
    }
}

I have defined some entities for testing the TypeBinding<TServiceType> class:

interface FooInterface {
  logFoo() : void;
}

interface BarInterface {
  logBar() : void;
}

interface FooBarInterface {
  logFooBar() : void;
}

// Notice default constructor
class Foo implements FooInterface {
  public logFoo(){ 
    console.log("foo"); 
  }
}

// Notice default constructor
class Bar implements BarInterface {
  public logBar(){ 
    console.log("bar"); 
  }
}

// Notice dependencies on FooInterface and  BarInterface on constructor
class FooBar implements FooBarInterface {
  public foo : FooInterface;
  public bar : BarInterface;
  public logFooBar(){ 
    console.log("foobar"); 
  }
  constructor(FooInterface : FooInterface, BarInterface : BarInterface) {
    this.foo = FooInterface;
    this.bar = BarInterface;
  }
}

I can use the TypeBinding<TServiceType> class with no issues with the classes Foo and Bar

var fooBinding = new TypeBinding<FooInterface>("FooInterface", Foo);
var barBinding = new TypeBinding<BarInterface>("BarInterface", Bar);

My problem comes when I try to use { new(): TServiceType ;} and the constructor of the class that implements TServiceType is not parameterless.

Argument of type 'typeof FooBar' is not assignable to parameter of type 'new () => FooBarInterface'.

var fooBarBinding = new TypeBinding<FooBarInterface>("FooBarInterface", FooBar);

How can work around this issue?

Thanks :)

@remojansen
Copy link
Contributor Author

I think I have fixed the issue by changing the class attribute:

implementationType : { new(): TServiceType ;},

to:

implementationType : { new(...args : any[]): TServiceType ;},

Will write some unit test con confirm.

Thanks...

@jklmli
Copy link

jklmli commented Apr 29, 2015

Clever! Thanks for this tidbit :)

@blackshadev
Copy link

Thanks for this, I was looking for a way to perform typechecking on constructors passed in a function parameter. The { new(...args : any[]): T ;} allowed me to do so.

Which means I can perform typechecking on decorator targets

function decor(oPar: {}): <TFunc extends { new (...args: any[]): A }>(target: TFunc) => void {    
    return function <TFunc extends { new (...args: any[]): A }>(target: TFunc): void {
        console.log(oPar, target);
    }
}

class A { id: string; }
// will error
@decor({})
class B { }

// Works
@decor({})
class C extends A { }

@microsoft microsoft locked and limited conversation to collaborators Jun 18, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants