我有一个功能图,具有不同的签名
const allMyFunctions = {
f1: () => Promise.resolve(1),
f2: (a: number) => a
};
还有一个抽象类,使用这些功能可以做一些事情:
abstract class MyClass {
protected abstract decorateMethod(...args: any[]): any;
decorateAll() {
return Object.keys(allMyFunctions)
.reduce((acc, key) => {
const f = allMyFunctions[key as keyof typeof allMyFunctions];
acc[key as keyof typeof allMyFunctions] = this.decorateMethod(f);
return acc;
},{} as {[index in keyof typeof allMyFunctions]: ReturnType<MyClass['decorateMethod']>});
}
}
因此,decorateAll
使用相同的键创建了一个新映射,但是每个函数都经过decorateMethod
,这是抽象的。
我现在可以实例化两个真实的类,如下所示:
class MyConstantClass extends MyClass {
protected decorateMethod(f: AnyFunction) {
return () => 2;
}
}
class MyIdentityClass extends MyClass {
protected decorateMethod<F extends AnyFunction>(f: F) {
return f;
}
}
const instance1 = new MyConstantClass();
const a = instance1.decorateAll().f1;
const instance2 = new MyIdentityClass();
const b = instance2.decorateAll().f2;
不幸的是,a
和b
的类型是any
,实际上它们应该是() => number
和(a:number) => number
。
看来,如果我在子类中复制粘贴decorateAll
实现,并用ReturnType<MyIdentity['decorateMethod']>
替换最后一行强制转换,那么它将起作用。但是这里有重复的逻辑,我想通过在第一位置使用抽象类来避免。
编辑:添加游乐场链接
答案 0 :(得分:1)
您可以使用多态this
来引用该类的当前类型。这将使您大致写出所需的内容
const allMyFunctions = {
f1: () => Promise.resolve(1),
f2: (a: number) => a
};
type AnyFunction = typeof allMyFunctions[keyof typeof allMyFunctions];
abstract class MyClass {
abstract decorateMethod(...args: any[]): any;
decorateAll() {
return Object.keys(allMyFunctions)
.reduce((acc, key) => {
const f = allMyFunctions[key as keyof typeof allMyFunctions];
acc[key as keyof typeof allMyFunctions] = this.decorateMethod(f);
return acc;
}, {} as {
[index in keyof typeof allMyFunctions]: ReturnType<this['decorateMethod']>
});
}
}
class MyConstantClass extends MyClass {
decorateMethod(f: AnyFunction) {
return () => 2;
}
}
class MyIdentityClass extends MyClass {
decorateMethod<F extends AnyFunction>(f: F) {
return f;
}
}
const instance1 = new MyConstantClass();
const a = instance1.decorateAll().f1; // () => number
const instance2 = new MyIdentityClass();
const b = instance2.decorateAll().f2; // This might not be what you want: (() => Promise<number>) | ((a: number) => number)
MyConstantClass
可以正常工作,它为所有函数() => number
返回,但是MyIdentityClass
返回对象中所有函数类型的并集。这是因为decorateMethod
返回与原始内容相同的信息的类型未被捕获。 decorateMethod
取得并并返回一个并,然后破坏类型。
答案 1 :(得分:0)
通过包含<T>
类型来使您的抽象类通用,并使decorateMethod
的结果为T
(或()=>T
)而不是any
。然后,这两个具体的类将扩展,例如MyClass<number>
(或MyClass<()=>number>
)。这样可以解决您的至少一种情况。
对于第二种情况,您的decorateMethod
取F
并返回F
,这并不是那么容易,我想用您的decorateMethod
来表达这一点实际上是不可能的。是通用的。我尝试执行此操作here,但是它不起作用-TS删除了泛型并返回了{}
。