下面我有一个返回布尔值的同步函数,我正在使用此装饰器@MakeAsync
来更改该函数。我很好奇在进行此更改后如何更新函数的返回类型。我尝试使用Promise<ReturnType<typeof original>>
,但失败了。
修饰器是否有可能覆盖方法的类型定义(参数和返回类型)?
function MakeAsync() {
console.log("f(): evaluated");
return function (target, key: string, descriptor: PropertyDescriptor) {
const original = descriptor.value;
if (typeof original === 'function') {
descriptor.value = async (...args): Promise<ReturnType<typeof original>> => {
return original(...args)
}
}
return descriptor;
}
}
class Example {
@MakeAsync()
doTrue (): Boolean {
return true
}
}
const e = new Example
console.log(e.doTrue())
答案 0 :(得分:0)
据我所知,装饰器不会改变类型。无论如何,我知道class decorators don't。您可能可以创建自己的函数,该函数采用类构造函数并返回具有修改后的原型方法的新类构造函数,并手动对其进行注释,但您不会为此使用装饰符表示法。装饰器仍然是函数调用的语法糖,因此,如果前者对您不起作用,则后者应该更灵活。
这是一种可能性:
type Asyncify<C extends new (...args: any) => any,
K extends keyof InstanceType<C>> = new (...args: ConstructorParameters<C>) => {
[P in keyof InstanceType<C>]: P extends K ?
InstanceType<C>[K] extends (...args: infer A) => infer R ?
(...args: A) => Promise<R> : InstanceType<C>[K]
: InstanceType<C>[K]
};
function makeMethodAsync<
C extends new (...args: any) => any,
K extends keyof InstanceType<C>
>(ctor: C, methodName: K): Asyncify<C, K> {
const c = class extends (ctor as any) { };
c.prototype[methodName as any] = async function (...args: any) {
return ctor.prototype[methodName].apply(this, args);
}
return c as any;
}
该实现使用大量的any
类型断言来使编译器静音。基本上,类型Asyncify<C, K>
接受构造函数类型C
和实例属性名称K
(应为方法名称;我不检查),然后求值为另一种构造类型其实例已为该方法Promise
返回一个K
,而其他属性则保持不变。该实现对其创建的新子类的原型执行类似的操作。 (我试图谨慎处理this
上下文;我认为您的装饰器可能会对类的实例访问其方法访问属性或其他方法的事情做坏事。)
让我们看看它是否有效:
const Example = makeMethodAsync(class Example {
prop = "hey";
syncDoTrue() {
console.log(this.prop)
return true;
}
asyncDoTrue() {
console.log(this.prop)
return true;
}
}, "asyncDoTrue");
const e = new Example();
const b = e.syncDoTrue(); // hey
console.log(b); // true
const r = e.asyncDoTrue(); // hey
console.log(r); // Promise { <state>: "fulfilled", <value>: true }
我想对我很好。希望能有所帮助;祝你好运!