Насколько я знаю, декораторы не видоизменяют типы. Я знаю, что декораторы класса не , во всяком случае. Вероятно, вы можете создать свою собственную функцию, которая принимает конструктор класса и возвращает новый конструктор класса с измененными методами-прототипами и вручную аннотирует, что делает, но вы не будете использовать для этого нотацию декоратора. Декораторы в любом случае являются синтаксическим сахаром для вызовов функций, поэтому, если первый не работает для вас, последний должен быть более гибким.
Вот одна из возможностей:
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 }
Мне кажется, выглядит хорошо. Надеюсь, это поможет;удачи!
Ссылка на код