TypeScript:处理静态方法的类型安全的类装饰器?

时间:2018-04-11 01:11:56

标签: typescript

如何编写一个正确处理静态方法的类型安全类装饰器?

具体来说,这个装饰器适用于没有静态方法的类

interface ITypeOf<T> {
    new(...args: any[]): T
}

function decorate<T>(cls: ITypeOf<T>): ITypeOf<T> {
    return cls
}

但是ITypeOf并不考虑静态属性,因此当它应用于具有静态属性的类时,编译失败并显示此错误:

@decorate
class Foo {
    static bar() {
        return 42
    }
}

产生错误:

Unable to resolve signature of class decorator when called as an expression.
  Type 'ITypeOf<Foo>' is not assignable to type 'typeof Foo'.
    Property 'bar' is missing in type 'ITypeOf<Foo>'.
function decorate<T>(cls: ITypeOf<T>): ITypeOf<T>

以下是一个工作示例: http://www.typescriptlang.org/play/#src=interface…

如何编写适用于具有静态成员的类的类型安全类装饰器?

2 个答案:

答案 0 :(得分:5)

装饰器的返回类型必须与它正在装饰的类类型兼容,因为装饰器的返回值将在运行时替换类。要实现这一点,我们必须使用表示类本身的泛型参数,它既是参数的类型,也是返回类型。因此,我们将返回一个与输入类(包括静态)具有相同结构的类,并且编译器将得到满足:

function decorate<TCtor extends ITypeOf<any>>(cls: TCtor): TCtor {
    return cls
}

@decorate
class Foo {
    static bar() {
        return 42
    }
}

要对要装饰的类添加限制,我们可以更加限制ITypeOf的类型参数:

// decorated class must have a field x: numeber
function decorate<TCtor extends ITypeOf<{ x: number }>>(cls: TCtor): TCtor {
    return cls
}

@decorate // error no instance x
class Foo { }
@decorate // ok
class Boo { x!: number }

我们还可以添加有关静态成员的限制

// decorated class must have a static field x: numeber
function decorate<TCtor extends ITypeOf<any> & { x: number }>(cls: TCtor): TCtor {
    return cls
}

@decorate // error no static x
class Foo { }
@decorate // ok
class Boo { static x: number }

答案 1 :(得分:0)

  

如何编写适用于类的类型安全类装饰器   与静态成员?

这取决于你在装饰者里面要做什么。

你可以简单地让decorator像这样完全通用:

function decorate<C>(cls: C) {
    return cls;
}

但是,这不会捕获有关C的任何信息,因此您无法对cls内的decorate做多少工作。

或者你可以有单独的通用参数,一个用于&#34;实例端&#34; cls和另一个用于&#34;静态&#34;:

interface ITypeOf<T> {
    new(...args: any[]): T
}

function decorate<I, S extends ITypeOf<I>>(cls: S): S {
    return cls
}


@decorate
class Foo {
    static bar() {
        return 42
    }

}