0

I get an error in TypeScript 2.4.2 on a generic class with a constraint not being compatible with the interface which is less strict. I get the following error:

ts/components/Schedule.ts(37,13): error TS2322: Type '{ personWeekView: PlanItemScheduleView; projectWeekView: PlanItemScheduleView; r...' is not assignable to type 'Map'. Property 'personWeekView' is incompatible with index signature. Type 'PlanItemScheduleView' is not assignable to type 'IPlanItemScheduleView'. Types of property 'onAddedItem' are incompatible. Type '(item: T, initial: boolean) => void' is not assignable to type '(item: T, initial: boolean) => void'. Types of parameters 'item' and 'item' are incompatible. Type 'T' is not assignable to type 'PlanItem'.

ts/views/PlanItemScheduleView.ts(2,18): error TS2420: Class 'PlanItemScheduleView' incorrectly implements interface 'IPlanItemScheduleView'. Types of property 'onAddedItem' are incompatible. Type '(item: T, initial: boolean) => void' is not assignable to type '(item: T, initial: boolean) => void'. Types of parameters 'item' and 'item' are incompatible. Type 'T' is not assignable to type 'PlanItem'.

ts/views/PlanItemScheduleView.ts(99,79): error TS2345: Argument of type 'this' is not assignable to parameter of type 'IControllerListener'. Type 'PlanItemScheduleView' is not assignable to type 'IControllerListener'. Types of property 'onAddedItem' are incompatible. Type '(item: T, initial: boolean) => void' is not assignable to type '(item: T, initial: boolean) => void'. Types of parameters 'item' and 'item' are incompatible. Type 'T' is not assignable to type 'PlanItem'.

Interfaces

namespace Planning {
    export interface IPlanItemScheduleView extends IView, IControllerListener<IPlanItem> {
        setTimespan(timespan: Timespan): void;
        getName(): string;
    }
}
namespace Planning {
    export interface IControllerListener<T> {
    /**
     * Notifies the listener that an item is added to the cache so it can add it to its view.
     * 
     * @template T
     * @param {T} item
     * @param {boolean} initial
     * 
     * @memberOf IControllerListener
     */
    onAddedItem<T>(item: T, initial: boolean): void;
    }
}

namespace Planning {
    export class PlanItemScheduleView<T extends PlanItem> implements IPlanItemScheduleView {

        public onAddedItem<T extends PlanItem>(item: T, initial: boolean): void {
            // implementation that needs properties on PlanItem
        }
    }
}

PlanItem is an abstract baseclass which is inherited by a few actual implementations. I have a few different kind of viwes that I construct like this:

  // Create the different views
  this._views = {
            personWeekView: new PlanItemScheduleView<Person>(this._options, this._logger, this),
            projectWeekView: new PlanItemScheduleView<Project>(this._options, this._logger, this),
            resourceWeekView: new PlanItemScheduleView<Resource>(this._options, this._logger, this),
        };

I thought I had this compiling before in an other version of tsc but I might be mistaken. How can I fix this?

1 Answer 1

2

You do not need the generic parameter on onAddedItem, you can use the class parameter if you want onAddedItem to take the same argument type as the class. You could make IPlanItemScheduleView generic, so as to pass the PlanItemScheduleView type parameter down to IControllerListener

export interface IControllerListener<T> {
  onAddedItem(item: T, initial: boolean): void;
}
export interface IPlanItemScheduleView<T extends IPlanItem>  extends IControllerListener <T> {

}
export class PlanItemScheduleView<T extends PlanItem> implements IPlanItemScheduleView<T> {
  public onAddedItem(item: T, initial: boolean): void {
      // implementation that needs properties on PlanItem
  }
}

Note: edited to take into account feedback.

Sign up to request clarification or add additional context in comments.

4 Comments

This makes the onAddedItem less safe because with your suggestion I can provide different derived types to the onAddedItem instead of narrowing it down to only the one type provided at construction time which is actually the reason for using a generic/templated class.
Your version does not restrict the type more than the type passed to the class. Are you saying that you would want onAddedItem to accept a type derived from PlanItem but not PlanItem itself
Yes, in case of a personWeekView instance I want only a Person to be the type of the parameter and not any other derived PlanItem types.
I changed the answer, now onAddedItem takes the same parameter type as the class, so you cannot call _views.personWeekView.onAddItem(new Project())

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.