TypedPropertyDecorator 泛型的奇怪行为

问题描述 投票:0回答:2

当我注意到一个非常奇怪的行为时,我试图在 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
方法,但我没有看到我做错了什么的明显原因。

typescript typescript-generics typescript-decorator
2个回答
0
投票

我稍微看了一下,似乎 attr 必须返回

TypedPropertyDescriptor

的精确类型

并且方法

method
返回消息,并且它不可能返回
void
,这就是它抱怨的原因。

尝试添加

   @a
    public async method(message: Message) {
        return message as void | Message;
    }

应该消除错误。

我宁愿用

TypedPropertyDescriptor<any>
代替


0
投票

装饰器很棘手。

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";
    }
}

TypeScript 游乐场

© www.soinside.com 2019 - 2024. All rights reserved.