我无法使用 Typescript 以通用方式解决这个问题,我将不胜感激!
目标是这样的(半伪代码)
interface MockFactory<F extends Factory> extends F {
deploy: (...args: Parameters<F.prototype.deploy>) => MockContract<F.prototype.deploy.returnValue>
}
为了更好地说明问题,我创建了一个 Playground,您可以在其中查看错误
答案 0 :(得分:3)
刚刚通过使用ReturnType和Parameters解决了,同样需要将接口转化为类型:
interface Contract {}
interface Factory {
deploy: (...args: any[]) => Contract;
}
class CustomContract implements Contract {}
class CustomFactory implements Factory {
deploy(x: number, y: number): CustomContract {
return {};
}
}
type MockContract<C extends Contract> = Contract & C & {
mockProperty: number;
}
type MockFactory<F extends Factory> = F & {
// deploy should have the parameters of the function deploy inside F (in this case CustomFactory)
// deploy should return a MockContract of the return type of the function deploy inside F (MockContract<CustomContract> in a generic way)
deploy: (...args: Parameters<F['deploy']>) => MockContract<ReturnType<F['deploy']>>
}
const example: MockFactory<CustomFactory> = {} as any;
example.deploy(1, 2);
答案 1 :(得分:2)
您可以使用(抽象)类,但接口也是可能的。在这种情况下,使工厂本身通用似乎是错误的举动。改为使合同类型通用。在玩了一会儿之后,我终于能够把它拼凑起来:
interface Contract { }
interface Factory<A extends any[], C extends Contract> {
deploy: (...args: A) => C;
}
// Some helper types
type FactoryArgs<F extends Factory<any, any>> = F extends Factory<infer A, any> ? A : never;
type FactoryContractType<F extends Factory<any, any>> = F extends Factory<any, infer C> ? C : never;
interface FactoryForClass<C extends new (...args: any) => Contract> {
//deploy: C extends new (...args: infer A) => infer T ? Factory<A, T>['deploy'] : never;
deploy: Factory<ConstructorParameters<C>, InstanceType<C>>['deploy'];
}
class CustomContract implements Contract {
constructor(a: number, b: number) { }
}
class CustomFactory implements FactoryForClass<typeof CustomContract> {
deploy(x: number, y: number): CustomContract {
return new CustomContract(x, y);
}
}
type MockContract<C extends Contract> = Contract & C & {
mockProperty: number;
}
type MockFactory<F extends Factory<any, any>> = F & {
deploy: (...args: FactoryArgs<F>) => MockContract<FactoryContractType<F>>;
}
const mockFactory: MockFactory<CustomFactory> = {
deploy(a: number, b: number) {
const customContract = new CustomContract(a, b);
const result: CustomContract & MockContract<CustomContract> = customContract as any;
result.mockProperty = 123;
return result;
}
};