打字稿条件返回类型:基于参数的对象或对象数组

时间:2021-03-04 22:02:45

标签: typescript typescript-typings

尽量保持简洁。问题出在 MyItemRepository.foo - 请参阅内嵌注释。

class MyModel {}

class MyItem extends MyModel {
  getFoo() {}
  getBar() {}
}

interface IMyItemData {
  foo: string;
  bar: string;
}

class MyRepository<MyEntity extends MyModel, IMyEntityData extends any> {
  protected getData(entities: MyEntity): IMyEntityData;
  protected getData(entities: MyEntity[]): IMyEntityData[];
  protected getData(entities: MyEntity | MyEntity[]): IMyEntityData | IMyEntityData[] {
    if (Array.isArray(entities)) {
      return this.getDataItems(entities);
    }
    return this.getDataItem(entities);
  }

  private getDataItem(entity: MyEntity): IMyEntityData {
    return null;
  }

  private getDataItems(entities: MyEntity[]): IMyEntityData[] {
    return [];
  }
}

class MyItemRepository extends MyRepository<MyItem, IMyItemData> {
  foo(surprise: MyItem | MyItem[]): IMyItemData[] {
    let item: MyItem;
    let items: MyItem[];

    const itemData = this.getData(item); // correctly resolves type to IMyItemData
    const itemsData = this.getData(items); // correctly resolves type to IMyItemData[]

    // here I get the error that 'no overload matches this call'
    const surpriseData = this.getData(surprise); // resolves type to IMyItemData & IMyItemData[]

    return castArray(surpriseData); // Lodash method
  }
}

const repo = new MyItemRepository();

const items = repo.foo(new MyItem()); // correctly resolves type to IMyItemData[]

还尝试检查 MyItemRepository.getData 中的实例,而不是检查是否传递了数组,但仍然存在同样的问题。

protected model: ModelConstructor<Entity>;

protected getData(entities: MyEntity | MyEntity[]): IMyEntityData | IMyEntityData[] {
  if (entities instanceof this.model) {
    return this.getDataItem(entities);
  }
}

我不想使用类型保护是 MyItemRepository.foo,因为我不关心 MyItemRepository.getData 的返回类型。没有它,有什么方法可以实现我想要的吗?

基本上我希望将 surpriseData 解析为 IMyItemData | IMyItemData[],而不是 IMyItemData & IMyItemData[]。不知道它是从哪里来的。

目前使用一个有点hacky的解决方案:

const surpriseData = this.getData(castArray(surprise));

1 个答案:

答案 0 :(得分:1)

重载函数的最后一行是实现签名,因此它不被视为重载之一。您在此处需要做的就是将最后一行输入两次——一次作为重载,一次作为实现。

protected getData(entities: MyEntity): IMyEntityData;
protected getData(entities: MyEntity[]): IMyEntityData[];
protected getData(entities: MyEntity | MyEntity[]): IMyEntityData | IMyEntityData[];
protected getData(entities: MyEntity | MyEntity[]): IMyEntityData | IMyEntityData[] {

这表示如果 entities 是任一输入类型,则数据是任一返回类型。重载是从上到下应用的,因此不必担心无意中扩大了更具体的类型。

Typescript Playground Link