具有通用类型的Typescript扩展接口导致约束错误的子类型

问题描述

我有一个抽象类,其认状态值在ResourceState接口内键入。尝试将扩展的State分配给抽象类的state属性时,出现以下错误。尽管仍然无法使用交叉路口,但我尝试了多种方法。我想要实现的是,我可以为state属性提供一个通用接口,以便除了认值之外,还可以添加更多值。

这是我得到的错误

输入'{项目:never []; isLoading:false;错误:字符串; }”不可分配给“状态”类型。 '{项目:永不[]; isLoading:false;错误:字符串; }”可分配给“状态”类型的约束,但可以使用约束“资源状态”的其他子类型实例化“状态”。

这是我的代码

export interface BaseItem {
  id: string;
  name: string;
}

export interface ResourceState < Item extends BaseItem > {
  items: Item[];
  selectedItem ? : Item;
  isLoading: boolean;
  error: string;
}

export abstract class Resource < Item extends BaseItem,State extends ResourceState < Item >,Mutations,Getters,Actions > {
  state: State = { // this is where the error occurs
    items: [],isLoading: false,error: '',}
}

解决方法

当您说State extends ResourceState<Item>时,是在说State必须符合ResourceState<Item>,但是由于这是一个通用类型参数,因此它可能不完全是ResourceState<Item>

想象一下:

interface MyState extends ResourceState<{ a: 123 }> {
  myCustomRequiredProperty: number
}

现在您将MyState作为State传递给班级,然后使用以下方法构造状态:

  state: State = { // this is where the error occurs
    items: [],isLoading: false,error: '',}

然后,您的state变量将不会使用myCustomRequiredProperty属性进行构造。

这是打字稿(试图)告诉您的错误。


如果您要在Resource类中构造状态变量,那么State不应是通用的,因为此类中的可执行代码无法知道通常可以通用的类型的所有属性因此,State不应extend ResourceState<Item>,它应该恰好是ResourceState<Item>

它看起来像这样:

export abstract class Resource<Item extends BaseItem> {
  state: ResourceState<Item> = {
    items: [],}
}

Playground


但是,如果您希望能够添加属性以声明状态,那么没有一些初始值就无法做到这一点。您需要以某种方式初始化那些未知的属性。为此,您可以使用上面的方法,但要使用一个接受完整状态的类型的构造函数,然后使用具有该信息的对象填充该类型的未知属性。

export abstract class Resource<
  Item extends BaseItem,State extends ResourceState<Item>
> {
  state: State

  constructor(initialState: State) {
    this.state = {
      ...initialState,// Fills in extended properties
      items: [],}
  }
}

Playground