当我注意到一个非常奇怪的行为时,我试图在 TypeScript (4.9.5) 中创建一个强类型装饰器。我能够在 TypeScript Playground 上创建它的最小复制品(链接如下)。这是代码片段:
type Message = { Body: string };
type Test = (message: Message) => Promise<void | Message>;
// This works as it should no complaints that this function does not respect Test type
const test: Test = async (message: Message) => ({ Body: 'hey' });
const a = (target: object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<Test>) => {
const og = descriptor.value;
console.log('Hey')
};
class A {
@a
// ^ This does not work as expected it's complaining that the function
// return type is not exactly Promise<void | Message>
public async method(message: Message): Promise<Message> {
return message;
}
}
当返回类型在提供的联合内时,为什么此示例中的装饰器会抛出错误?有没有办法解决这个问题?
我期望由于被装饰的方法具有匹配的参数和尊重
Promise<void | Message>
联合的返回类型,因此将允许使用此装饰器而不会出现 TypeScript 抱怨。
在我的代码片段中,我们可以看到在
TypedDecoratorProperty
之外,这按预期工作,但在传递到泛型时却不起作用。它抱怨类型中的 set
方法,但我没有看到我做错了什么的明显原因。
我稍微看了一下,似乎 attr 必须返回
TypedPropertyDescriptor
的精确类型
并且方法
method
返回消息,并且它不可能返回void
,这就是它抱怨的原因。
尝试添加
@a
public async method(message: Message) {
return message as void | Message;
}
应该消除错误。
我宁愿用
TypedPropertyDescriptor<any>
代替
MethodDecorator
可能会替换该方法的实现,但不能更改其类型。因为该方法可能会被替换为确实返回 Promise<void>
的函数,所以它不再适合 (...) => Promise<Message>
的签名
换句话说,你的装饰器只读取属性,但 TypeScript 假设它也写入它。
目前没有内置方法来创建“仅出”装饰器,因此我创建了 typesafe-decorators 库。我相信这对您的情况有帮助。
import { TypedMethodDecorator } from 'typesafe-decorators';
type Message = { Body: string };
type Test = (message: Message) => Promise<void | Message>;
// This works as it should
const test: Test = async (message: Message) => ({ Body: 'hey' });
const a: TypedMethodDecorator<Test, 'get'> = (target, propertyKey, descriptor) => {
const og = descriptor.value;
console.log('Hey')
};
class A {
@a // works
public async method(message: Message) {
return message;
}
@a // type error
public async method2(message: Message) {
return "string";
}
}