【问题标题】:How to compose multiple TypeScript class decorators?如何组合多个 TypeScript 类装饰器?
【发布时间】:2016-12-25 20:35:50
【问题描述】:

我有一个类装饰器家族,我在许多类中重复使用它们。类似的东西:

@foo
@bar
@baz
export class MyClass { /* ..... */ }

由于我在多个类中使用这三个装饰器,我真的很想将其分解为一个装饰器,如下所示:

@standard
export class MyClass { /* ... */ }

我尝试创建一个新的类装饰器,它像这样链接装饰器调用:

export function standard<ReturnType>(ctor: Constructor<ReturnType>) {
    return baz(bar(foo(ctor)));
}

TypeScript 手册说应用多个装饰器的评估应该类似于函数组合,这就是为什么我认为我应该能够将它们链接在一起。但是,在编译时(使用 TypeScript 1.8)我收到类似于

的错误

Unable to resolve signature of class decorator when called as an expression. Type 'Constructor&lt;ReturnType&gt;' is not assignable to type 'void'.

有没有办法可以构造这个“包装器”装饰器来简化我的代码?

【问题讨论】:

  • 当我填写空白时,您的代码对我来说很好。您可以发布一个重复您的错误的完整示例吗?
  • 试图给你一个更好的例子引导我解决问题!在下面查看我的答案。

标签: typescript decorator


【解决方案1】:

为了尝试为@David 构建我的问题的更完整版本,我发现了哪里出了问题。

一个更完整的例子:

interface Constructor<T> { new(...args: any[]): T }
interface A { a: number; }
interface B { b: number; }
interface C { c: number; }

function foo(Target: Constructor<A>): Constructor<A>{ 
    // do some stuff to the constructor
    return Target;
}
function bar(Target: Constructor<B>): Constructor<B> { 
    // do some stuff to the constructor
    return Target;
}
function baz(Target: Constructor<C>): Constructor<C> {
    // ....
    return Target;
}

function standard(ctor: Constructor<A & B & C>): Constructor<A & B & C> {
    return baz(bar(foo(ctor)));
}

@foo
@bar
@baz
class MyClass implements A, B, C { a=1;b=2;c=3;d=6; }

在我的实际代码中有一些隐含的输入,这在某种程度上隐藏了我的问题。显然我无法正确读取编译器输出。

问题在于我如何声明我的装饰器:

function foo(Target: Constructor<A>): Constructor<A> { }

需要

function foo<T extends A>(Target: Constructor<T>): Constructor<T> {}

我注意到如果我将装饰器中的返回类型设置为any,编译错误就会消失。额外的通用参数让类型信息干净地流过装饰器。否则,我相信它(基本上)看到Constructor&lt;MyClass&gt; 无法分配Constructor&lt;A&gt; 的实例(因为A 缺少其他接口)。同样奇怪的是,如果我在MyClass 中添加d 的声明,我会在装饰器中弹出更多错误。

所以最后 - 使用类装饰器时,请小心使用泛型,或者直接返回 any

【讨论】:

    【解决方案2】:

    你可以试着这样说:

    export function foo(target: any)
    {
        return target;
    }
    
    export function bar(target: any)
    {
        return target;
    }
    
    export function baz(target: any)
    {
        return target;
    }
    
    export function standard<T>() 
    {
        return (target: { new(): T}) =>
        {
            return foo(bar(baz(target)));
        }
    }
    
    @foo
    @bar
    @baz
    export class MyClass  { /* ... */ }
    
    @standard<MyClass>()
    export class MyClassA { /* ... */ }
    

    【讨论】:

      猜你喜欢
      • 2019-01-28
      • 2022-08-15
      • 2015-08-05
      • 1970-01-01
      • 2017-11-15
      • 2018-04-06
      • 2018-06-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多