2016-10-09 14 views
1

Typescriptでクラスデコレータを実装しようとしています。だから私は引数としてクラスを取る関数を持っています。タイプ 'any'はコンストラクタ関数の型ではありません

const decorate = function() 
{ 
    return function (target: any) 
    { 
    return class myExtendClass extends target{} 
    }; 
}; 

目標は好き、それを使用することです:

@decorate() 
class Something{} 

は、残念ながら、私はtype any is not a constructor function typeを取得しています。どのように私は私が欲しいものを達成することができますか?

+0

を参照してください。多分Function' 'に' any'を変更してみてください? http://stackoverflow.com/questions/29775830/how-to-implement-a-typescript-decoratorおよびhttps://blogs.msdn.microsoft.com/typescript/2015/04/30の「クラスデコレータ」を確認してください。/announceus-typescript-1-5-beta/ –

+0

@SayanPalはすでにFunctionを試していて、動作していません。私はそれが有効なTSコードでなければならないので、Reflect APIを使用しなければならないのがちょっと変わっています:) –

+0

あなたの例でクラスを拡張するためにデコレータを使用しようとしています。ここの主な問題?または、あなたの質問はちょうどデコレータを働かせることについてですか? – Alex

答えて

4

my question is why this code doesnt work, since its valid js

あなたが動作しないによって何を意味するかに依存していること。

生成されたjavascriptは有効であり、動作します。しかし、TypeScriptは非常に厳しく、TSのルールに準拠していないコードを書くと文句を言うでしょう。たとえそれがしばしばうまくいくと思いますし、とにかくコンパイルされたjsを与えるでしょう。

あなたがしようとしている問題は、TSがデコレータを介してクラスを拡張することをサポートしていないことです。それは動作するjsを生成しますが、TSはこれを行うとき何が起こっているのか理解していません。例えば

const decorate =() => (target: typeof Cat) => 
{ 
    return class Lion extends target 
    { 
     public Roar =() => console.log("Roaar") 
    } 
} 

@decorate() 
class Cat 
{ 
    public Purr =() => console.log("Purr purr"); 
} 

var lion = new Cat(); 
lion.Roar(); // Error in TypeScript but working in js 

あなたがそれを実行するとき、これは動作しますが、TSはあなたがデコレータの中に何をしているかを理解していないので、それはクラスCatが実際にLionであることを知りません。

TSにデコレータのクラス変異を理解させることについては、feature requestがありますが、現時点ではサポートされていません。

このようなデコレータでは、クラスの変更を避けることをお勧めします。そして、たとえそれがうまくいくとしても、今のところあなたの例の中のポイントは見えません。それは直感的ではなく、すべてSomethingが特定のプロパティを持つことを望むならば、それを直接拡張することができます:Something extends MyReusableProperties

+1

私は他の方法でそれを達成することができます、なぜ私はデコレータがよりエレガントな、それは問題ではない全体のコードを提供することはできません。あなたの答えはThx。 –

+0

あなたの本当のユースケースを見るのは面白いでしょう。たとえば、ミックスインの方がいいでしょう。 – Alex

1

あなたは試みることができる:

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

function decorate() 
{ 
    return function (target: Newable<Object>) 
    { 
    return class myExtendClass extends target { 
     public someOtherProp: string; 
     publicconstructor() { 
     this.someOtherProp = "test2"; 
     }  
    } 
    }; 
}; 

をしかし、その後、あなたは新しいエラーが発生します。

// Error: Type 'typeof myExtendClass' is 
// not assignable to type 'typeof Something'. 
@decorate() 
class Something{ 
    public someProp: string; 
    publicconstructor() { 
    this.someProp = "test"; 
    } 
} 

あなたはそれを修正しようとすることができます:

あなたが得る
function decorate() 
{ 
    return function (target: Newable<Object>) 
    { 
    class myExtendClass extends target { 
     public someOtherProp: string; 
     publicconstructor() { 
     this.someOtherProp = "test2"; 
     } 
    } 
    return (<any>myExtendClass); // notice casting! 
    }; 
}; 

そして再び別のエラー:

let something = new Something(); 
console.log(something.someProp); 

// Property 'someOtherProp' does not 
//exist on type 'Something'. 
console.log(something.someOtherProp); 

最後に、あなたがいずれかにキャストすることによって、それを解決することができ:もちろん

console.log((<any>something).someOtherProp); // More casting! 

これは理想的なソリューションではありません。私の代わりに、次のような何かを行うしようとするだろう。

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

function decorate() 
{ 
    return function (target: Newable<Object>) 
    { 
    class myExtendClass extends target { 
     public someOtherProp: string; 
     publicconstructor() { 
     this.someOtherProp = "test2"; 
     } 
    } 
    return (<any>myExtendClass); 
    }; 
}; 

function applyDecorator<T,TDecorated>(decorator, ctr): Newable<TDecorated> { 
    // Decorators are just functions, you don't need @ symbol to use them :) 
    let decorated: Newable<TDecorated> = <any>decorator()(ctr); 
} 

interface ISomething { 
    someProp: string; 
} 

interface ISomethingElse extends Something { 
    someOtherProp: string; 
} 

class Something implements ISomething { 
    public someProp: string; 
    publicconstructor() { 
    this.someProp = "test"; 
    } 
} 

let SomethingElse = applyDecorator<ISomething, ISomethingElse>(decorate, Something); 

let something = new SomethingElse(); 
console.log(something.someProp); 
console.log(something.someOtherProp); 

はそれが役に立てば幸い:)

+1

thx !.私は答えを受け入れる前にそれを数日間開いたままにしておきます。誰かがより洗練された解決策(私は疑います)を思いついたかもしれません。とにかくThx: –

0

問題はデコレータ関数の署名にあります。 function (target: any)からfunction <T extends { new (...args: any[]): {} }>に変更してください。声明class myExtendClass extends targetがエラーなしではそれがJavaScriptで呼ばれるようクラス別名コンストラクタ関数にする必要がありターゲットを動作させるためには、単純な、それを置くために 。 に拡張することはできませんが、クラス(コンストラクタ関数)には拡張できません。 ここで、制約付きジェネリック型Tは、ターゲットをクラス(コンストラクタ関数)として制約しています。したがって、extendステートメントはエラーなしで動作します。ここで は一例です:

const decorate = function() 
{ 
    return function <T extends { new (...args: any[]): {} }> 
     (target: T) 
    { 
     return class myExtendClass extends target{ 
      anotherProperty = 10; //assigning class property here 
      propertyFromDecorator = "new property from decorator" // new property 
    } 
    }; 
}; 


@decorate() 
class Something{ 
    myProp: string; 
    anotherProperty:number; 
    constructor() { 
     this.myProp = "my property"; 
    } 
} 

var someThing = new Something(); 
console.log(someThing); 

フォアは、よりTypescript Decorators page on github

関連する問題