TypeScript类型泛型无法正确推断类型

时间:2018-11-07 13:40:41

标签: typescript

考虑以下代码:

interface Entity<T extends DataFetcherImp> {
  name: string,
  fetcher: () => T
}

type UUID = string;

declare abstract class DataFetcherImp {
  public static fetch(id: UUID);
}

class TestFetcher implements DataFetcherImp {
  public static async fetch(id: UUID): Promise<TestFetcher> {
    return new TestFetcher(id);
  }

  constructor(private id: UUID) {
    // perform some io
  }
}

class OtherTestFetcher implements DataFetcherImp {
  public static async fetch(id: UUID): Promise<OtherTestFetcher> {
    return new OtherTestFetcher(id);
  }

  constructor(private id: UUID) {
    // perform some other io
  }
}

class DataFetcher_Broken {
  public async getData<T extends DataFetcherImp>(entity: Entity<T>, id: UUID): Promise<T> {
    return await entity.fetcher().fetch(id); // [2339] Property 'fetch' does not exist on type 'T'.
  }
}

class DataFetcher_Working {

  public async getData(entity: Entity<typeof TestFetcher>, id: UUID): Promise<TestFetcher>;
  public async getData(entity: Entity<typeof OtherTestFetcher>, id: UUID): Promise<OtherTestFetcher>;
  public async getData(entity: Entity<typeof TestFetcher | typeof OtherTestFetcher>, id: UUID): Promise<TestFetcher | OtherTestFetcher> {
    return await entity.fetcher().fetch(id);
  }
}

据我所知,类DataFetcher_Broken应该正在工作。但是tsc输出错误:[2339] Property 'fetch' does not exist on type 'T'.似乎编译器希望在类型T上存在非静态方法获取。 但是该方法必须是静态的,因为使用了库,该库仅在通用抽象类上提供静态方法。

如您所见,类DataFetcher_Working可以完成工作,但是还有另一个问题。该类如何扩展以与实现DataFetcherImp抽象的其他类一起使用?同样,对于课程,我们无法控制? 假设DataFetcher实用程序类的某些用户创建了一个类YetAnotherFetcher。然后,如果不修改方法签名,则不能将此类与DataFetcher_Working一起使用。因此,该方法不能包含在库中。

const df = new DataFetcher_Working();
df.getData({
    name: 'yaf',
    fetcher: () => YetAnotherFetcher // [2322] Type 'typeof YetAnotherFetcher' is not assignable to type 'typeof OtherTestFetcher'.  Types of property 'fetch' are incompatible.    Type '(id: string) => Promise<YetAnotherFetcher>' is not assignable to type '(id: string) => Promise<OtherTestFetcher>'.      Type 'Promise<YetAnotherFetcher>' is not assignable to type 'Promise<OtherTestFetcher>'.        Type 'YetAnotherFetcher' is not assignable to type 'OtherTestFetcher'.          Types have separate declarations of a private property 'id'.
}, 'd6413b62-5bc7-4670-a28e-d14c822d1dd8');

因此,DataFetcher_Broken中的通用方法是唯一的方法。

已经尝试了以下修改但不起作用:

1。

class DataFetcher_Broken {
  public async getData<T extends DataFetcherImp>(entity: Entity<T>, id: UUID): Promise<T> {
    return await (entity.fetcher() as any as typeof DataFetcherImp).fetch(id);
  }
}

此更改允许

const df = new DataFetcher_Broken();
df.getData({ name: 'completeDesaster', fetcher: () => Object }, 'd6413b62-5bc7-4670-a28e-d14c822d1dd8');

但是Object没有静态方法fetch

2。

class DataFetcher_Broken {
  public async getData<T extends DataFetcherImp>(entity: Entity<T>, id: UUID): Promise<T> {
    return await (entity.fetcher() as DataFetcherImp).fetch(id); // [2576] Property 'fetch' is a static member of type 'DataFetcherImp'
  }
}

3。

interface Entity<T extends DataFetcherImp> {
  name: string,
  fetcher: () => typeof DataFetcherImp
}

这种更改可能是有道理的,但是实体T的类型fetcher不再适用于const df = new DataFetcher_Broken(); df.getData({ name: 'willNotCompile', fetcher: () => TestFetcher }, 'd6413b62-5bc7-4670-a28e-d14c822d1dd8'); // [2322] Type 'typeof TestFetcher' is not assignable to type 'typeof DataFetcherImp'. 属性,并且会产生另一个错误:

TestFetcher

任何建议,如何使它正常工作?

TS Playground: minimal example.(将静态函数复制到{{1}}的原型的部分省略了)

1 个答案:

答案 0 :(得分:0)

由于fetch是静态的,因此实际上它不存在于DataFetcherImp的实例上,而仅存在于typeof DataFetcherImp上。

以下是消除了错误(T extends typeof DataFetcherImp)的更改:

class DataFetcher_Broken {
  public async getData<T extends typeof DataFetcherImp>(entity: Entity<T>, id: UUID): Promise<T> {
    return await entity.fetcher().fetch(id);
  }
}