Home > Net >  TS2322 : Type is both not assignable and assignable error, what does that mean?
TS2322 : Type is both not assignable and assignable error, what does that mean?

Time:09-28

I am trying to wrap my head around this. I have been working with generics in Java and C#, but only recently in TypeScript. So, can someone please explain to me this madness?

constructor FooAdapter(): FooAdapter

Type 'FooAdapter' is not assignable to type 'A'.

'FooAdapter' is assignable to the constraint of type 'A', but 'A' could be instantiated with a different subtype of constraint 'FooAdapter'.

ts(2322)

From the following snippet:

interface IFoo {}

interface IAdapter<F extends IFoo> {
   getFoo():F
}

abstract class AbstractFoo<F extends IFoo> {
   abstract something<A extends IAdapter<F>>():A;
}


class Foo implements IFoo {}
class FooAdapter implements IAdapter<Foo> {
   getFoo() { return new Foo(); }
}

class FooFactory extends AbstractFoo<Foo> {
   something<A extends FooAdapter>():A {
      return new FooAdapter();  // <--- ts(2322) here
   }   
}

How to fix this error?

CodePudding user response:

The issue is that FooAdapter is not A, FooAdapter may only be the parent class of A.

Your options here are:

A) Make something's return more generic so that it is happy with new FooAdapter():

interface IFoo {}

interface IAdapter<F extends IFoo> {
   getFoo():F
}

abstract class AbstractFoo<F extends IFoo> {
   abstract something(): IAdapter<F>;
}


class Foo implements IFoo {}

class FooAdapter implements IAdapter<Foo> {
   getFoo() { return new Foo(); }
}

interface IHasEmptyConstructor<T> {
    new(): T
}

class FooFactory extends AbstractFoo<Foo> {
   something(): IAdapter<Foo> {
      return new FooAdapter();
   }   
}

const fooFactory = new FooFactory();

fooFactory.something();

B) Make something return A instead of FooAdapter:

interface IFoo {}

interface IAdapter<F extends IFoo> {
   getFoo():F
}

abstract class AbstractFoo<F extends IFoo> {
   abstract something<A extends IAdapter<F>>(adapter: IHasEmptyConstructor<A>):A;
}


class Foo implements IFoo {}

class FooAdapter implements IAdapter<Foo> {
   getFoo() { return new Foo(); }
}

interface IHasEmptyConstructor<T> {
    new(): T
}

class FooFactory extends AbstractFoo<Foo> {
   something<A extends FooAdapter>(adapter: IHasEmptyConstructor<A>): A {
      return new adapter();
   }   
}

const fooFactory = new FooFactory();

fooFactory.something(FooAdapter);
  • Related