Home > OS >  How can I pass this to an interface used in a property of this?
How can I pass this to an interface used in a property of this?

Time:06-24

I am trying to describe a property that holds event listeners. The listeners are called with the object firing the event as first argument. When I try to pass "this" as a Generic argument to the events interface. I get the error: " Argument of type 'typeof Child' is not assignable to parameter of type 'typeof Base'"

interface BaseEvents<me extends Base> {
    render: (me:me) => void
}

class Base {
    public listeners?:BaseEvents<this>
}

class Child extends Base {
    foo() {
    }
}

function create<T extends typeof Base>(cls: T) {
    return new cls;
};

const c = create(Child);

Full error:

Argument of type 'typeof Child' is not assignable to parameter of type 'typeof Base'.
    Construct signature return types 'Child' and 'Base' are incompatible.
    The types of 'listeners' are incompatible between these types.
    Type 'BaseEvents<Child> | undefined' is not assignable to type 'BaseEvents<Base> | undefined'.
        Type 'BaseEvents<Child>' is not assignable to type 'BaseEvents<Base>'.
        Property 'foo' is missing in type 'Base' but required in type 'Child'.ts(2345)

Does anybody know how I can avoid this error?

Playground link

CodePudding user response:

You need to slightly update BaseEvents

interface BaseEvents<Me extends Base> {
    render: <T extends Me>(me: T) => void
}

class Base {
    public listeners?: BaseEvents<this>
}

class Child extends Base {
    foo() { }
}


function create<T extends typeof Base>(cls: T) {
    return new cls();
};

const c = create(Child); // ok

Playground

This is because Me in BaseEvents in in contravariant position. For instance, try to write BaseEvents in this way:

interface BaseEvents<Me extends Base> {
    render: Me
}

You will see that there is no more error in const c = create(Child);

CodePudding user response:

Typescript Playground Link

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

interface BaseEvents<Me extends Base> {
  render: (me: Me) => void
}


class Base {
  public listeners?: BaseEvents<this>
}

class Child extends Base {
  foo() {
  }
}

function create<T extends Base>(cls: Type<T>) {
  return new cls;
};

const c = create(Child);
  • Related