2017-04-18 78 views
0

我已经尝试了几种不同的方法来在TypeScript中声明装饰器函数,使装饰类实现接口。事情是这样的:实现接口的TypeScript装饰器声明

interface IValidatable { 
    checkValidation:() => boolean; 
} 

function validated<T>(Class: {new():T}): {new():T & IValidatable} { 
    Class.prototype.checkValidation =() => true; 
    return Class as {new():T & IValidatable}; 
} 

鉴于上述情况,我希望我可以那么做这样的事情:

@validated 
class Foo { 

} 

let f = new Foo(); 
let isValid = f.checkValidation(); 

但最后一行被标记为错误(“财产‘checkValidation’呢在'Foo'类型上不存在。“)。

以下确实在这个意义上工作,它并不会产生错误:

let ValidatedFoo = validated(Foo); 
let vf = new ValidatedFoo(); 
let isValid2 = vf.checkValidation(); 

有没有办法制定装饰声明使得第一用法示例不产生错误?

+2

看来这是一段时间以来一直存在的问题https://github.com/Microsoft/TypeScript/issues/4881 –

回答

1

我不认为你可以修复它,以便装饰器改变编译器认为Foo类的方式。
装饰器在运行时工作不能编译时间,所以当你实例化Foo时,编译器会看到Foo

我能想到的以下三个选项:

(1)铸造实例:

let f = new Foo() as Foo & IValidatable; 
let isValid = f.checkValidation(); 

(2)铸类的交点:

interface FooConstructor { 
    new(): Foo & IValidatable; 
} 

let f = new (Foo as FooConstructor)(); 
let isValid = f.checkValidation(); 

(3 )使用工厂功能:

function fooFactory(): Foo & IValidatable { 
    return new Foo() as Foo & IValidatable; 
} 

let f = fooFactory(); 
let isValid = f.checkValidation(); 

code in playground

+0

感谢您的回复。如果通过“装饰器在运行时工作而不编译时间,那么当你实例化Foo时,编译器会看到Foo。”你是在暗示这是不可能的,即使原则上,我认为这是不正确的。这就是为什么我将“工作”的例子包括进去的原因:在类似的情况下,TS可以做出正确的推断。 –

+0

我并不是说“这永远不能工作”,现在是这样。如果编译器用'validate(Foo)'替换'Foo'的定义(这是你的工作示例),它就可以工作。它也可以在运行时工作,因为js代码有这样的内容:'Foo = __decorate([validated],Foo)'(它也是一样的,只发生在运行时) –