考虑以下代码:
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}}的原型的部分省略了)
答案 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);
}
}