【问题标题】:Typescript generic with constraint isn't assignable to generic interface带有约束的打字稿泛型不能分配给泛型接口
【发布时间】:2018-02-09 06:06:20
【问题描述】:

我在 TypeScript 2.4.2 的泛型类中遇到错误,其约束与不太严格的接口不兼容。我收到以下错误:

ts/components/Schedule.ts(37,13): error TS2322: Type '{ personWeekView: PlanItemScheduleView; projectWeekView:PlanItemScheduleView; r...' 不能分配给类型 'Map'。 属性“personWeekView”与索引签名不兼容。 类型“PlanItemScheduleView”不可分配给类型“IPlanItemScheduleView”。 属性“onAddedItem”的类型不兼容。 类型 '(item: T, initial: boolean) => void' 不可分配给类型 '(item: T, initial: boolean) => void'。 参数“item”和“item”的类型不兼容。 类型“T”不可分配给类型“PlanItem”。

ts/views/PlanItemScheduleView.ts(2,18):错误 TS2420:“PlanItemScheduleView”类错误地实现了“IPlanItemScheduleView”接口。 属性“onAddedItem”的类型不兼容。 类型 '(item: T, initial: boolean) => void' 不可分配给类型 '(item: T, initial: boolean) => void'。 参数“item”和“item”的类型不兼容。 类型“T”不可分配给类型“PlanItem”。

ts/views/PlanItemScheduleView.ts(99,79):错误 TS2345:“this”类型的参数不可分配给“IControllerListener”类型的参数。 类型“PlanItemScheduleView”不可分配给类型“IControllerListener”。 属性“onAddedItem”的类型不兼容。 类型 '(item: T, initial: boolean) => void' 不可分配给类型 '(item: T, initial: boolean) => void'。 参数“item”和“item”的类型不兼容。 类型“T”不可分配给类型“PlanItem”。

接口

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 是一个抽象基类,由一些实际实现继承。我有几种不同的观点,我是这样构建的:

  // 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),
        };

我以为我之前在其他版本的 tsc 中进行过编译,但我可能弄错了。我该如何解决这个问题?

【问题讨论】:

    标签: typescript generics


    【解决方案1】:

    onAddedItem 不需要泛型参数,如果您希望onAddedItem 采用与类相同的参数类型,则可以使用类参数。您可以将IPlanItemScheduleView 设为泛型,以便将PlanItemScheduleView 类型参数向下传递给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
      }
    }
    

    注意:已编辑以考虑反馈。

    【讨论】:

    • 这使得 onAddedItem 不太安全,因为根据您的建议,我可以为 onAddedItem 提供不同的派生类型,而不是将其缩小到仅在构造时提供的一种类型,这实际上是使用泛型的原因/模板类。
    • 您的版本对类型的限制不超过传递给类的类型。您是说您希望 onAddedItem 接受从 PlanItem 派生的类型,但不接受 PlanItem 本身
    • 是的,对于 personWeekView 实例,我只希望 Person 成为参数的类型,而不是任何其他派生的 PlanItem 类型。
    • 我改了答案,现在onAddedItem和类的参数类型一样,所以不能调用_views.personWeekView.onAddItem(new Project())
    猜你喜欢
    • 1970-01-01
    • 2019-09-23
    • 1970-01-01
    • 1970-01-01
    • 2021-04-20
    • 2022-11-23
    • 2020-08-03
    • 2019-06-08
    • 1970-01-01
    相关资源
    最近更新 更多