使用 TypeScript 装饰器和 promises 并正确输入?
Using TypeScript decorators and promises with proper typing?
我写了一个 buffered
装饰器,它通过返回 Promise
(在执行期间)按预期工作。但是,为了让 tsc
转译器满意,我不得不用 any
转换装饰函数,然后(在下面的示例中)用 Promise<number>
.
如何避免额外的转换?装饰器甚至可以修改装饰函数的签名吗?例如,我如何编写一个 @buffered
装饰器,它采用方法函数 f
(其中 returns number
),而装饰函数 @buffered f
returns一个Promise<number>
(不是只是一个number
)?:
import { decorator as buffered } from '@dizmo/functions-buffered';
class Class {
@buffered(100) // i.e. 100ms delay
public f1(t: Date): number {
return new Date().getTime() - t.getTime();
}
@buffered // i.e. defaults to 200ms delay
public f2(t: Date): number {
return new Date().getTime() - t.getTime();
}
}
const p: Promise<number>
= new Class().f1(new Date()) as any;
p.then((res: number) => { console.debug(res); });
我可以这样写:
const p: Promise<number> = new Class().f1(new Date());
p.then((res: number) => { console.debug(res); });
但是,我得到以下输出:
[ts] Type 'number' is not assignable to type 'Promise<number>'.
然而,我实际上应该只能写:
const p = new Class().f1(new Date());
p.then((res: number) => { console.debug(res); });
但是 p
被识别为 number
而不是 Promise
:
[ts] Property 'then' does not exist on type 'number'.
@buffered
装饰器的实现位于:
请注意,当我想使用 200ms
.
的默认延迟时,由于我希望删除 @buffered
装饰器的括号,因此实现具有额外的复杂性
装饰者不能改变他们正在装饰的 class 的结构。这是一个设计限制。有一项针对 change this 的提议,但它似乎不是优先事项(如果它对你很重要,也许可以投票支持 GitHub 问题)
如果我们想要转换所有方法,我们可以使用映射类型,但我们不能将映射类型转换仅应用于修饰的属性,因此在这种情况下这不是一个可行的解决方案。
更好的选择是在 class 中直接输入正确的 return。我们可以使用 async
:
对代码进行最少的更改来做到这一点
class Class {
@buffered(100) // i.e. 100ms delay
// use async and return a promise instead of a number
public async f1(t: Date): Promise<number> {
return new Date().getTime() - t.getTime();
}
@buffered // i.e. defaults to 200ms delay
public async f2(t: Date) { // no need to specify the return type will be inferred correctly to Promise<number>
return new Date().getTime() - t.getTime();
}
}
const p: Promise<number> = new Class().f1(new Date()); // works fine
p.then((res: number) => { console.debug(res); });
我写了一个 buffered
装饰器,它通过返回 Promise
(在执行期间)按预期工作。但是,为了让 tsc
转译器满意,我不得不用 any
转换装饰函数,然后(在下面的示例中)用 Promise<number>
.
如何避免额外的转换?装饰器甚至可以修改装饰函数的签名吗?例如,我如何编写一个 @buffered
装饰器,它采用方法函数 f
(其中 returns number
),而装饰函数 @buffered f
returns一个Promise<number>
(不是只是一个number
)?:
import { decorator as buffered } from '@dizmo/functions-buffered';
class Class {
@buffered(100) // i.e. 100ms delay
public f1(t: Date): number {
return new Date().getTime() - t.getTime();
}
@buffered // i.e. defaults to 200ms delay
public f2(t: Date): number {
return new Date().getTime() - t.getTime();
}
}
const p: Promise<number>
= new Class().f1(new Date()) as any;
p.then((res: number) => { console.debug(res); });
我可以这样写:
const p: Promise<number> = new Class().f1(new Date());
p.then((res: number) => { console.debug(res); });
但是,我得到以下输出:
[ts] Type 'number' is not assignable to type 'Promise<number>'.
然而,我实际上应该只能写:
const p = new Class().f1(new Date());
p.then((res: number) => { console.debug(res); });
但是 p
被识别为 number
而不是 Promise
:
[ts] Property 'then' does not exist on type 'number'.
@buffered
装饰器的实现位于:
请注意,当我想使用 200ms
.
@buffered
装饰器的括号,因此实现具有额外的复杂性
装饰者不能改变他们正在装饰的 class 的结构。这是一个设计限制。有一项针对 change this 的提议,但它似乎不是优先事项(如果它对你很重要,也许可以投票支持 GitHub 问题)
如果我们想要转换所有方法,我们可以使用映射类型,但我们不能将映射类型转换仅应用于修饰的属性,因此在这种情况下这不是一个可行的解决方案。
更好的选择是在 class 中直接输入正确的 return。我们可以使用 async
:
class Class {
@buffered(100) // i.e. 100ms delay
// use async and return a promise instead of a number
public async f1(t: Date): Promise<number> {
return new Date().getTime() - t.getTime();
}
@buffered // i.e. defaults to 200ms delay
public async f2(t: Date) { // no need to specify the return type will be inferred correctly to Promise<number>
return new Date().getTime() - t.getTime();
}
}
const p: Promise<number> = new Class().f1(new Date()); // works fine
p.then((res: number) => { console.debug(res); });