2017-12-14 8 views
0

であれば、私はいくつかのtypescriptですインタフェース、抽象クラスとサブクラスを実装しましたサブクラスのメソッドを許可していません。ボックスにはAnimalのようなものがあります。この例では、SnakeまたはOwlです。活字体は、変数がスーパータイプ

BoxOwlで内部に作成できます。

let box = new Box(new Owl()); 

そして今問題 - スーパークラスで宣言された任意の方法を用いて、完全に罰金です:

box.animal.sound(); // this is fine 

いますが、フクロウを見ることができるように、追加の機能fly()を持っているとハエがAnimalに宣言されていないのでスロー:

box.animal.fly(); // Property 'fly' does not exist on type 'Animal'. 

通常の変数を作成する場合も同様です。

let animal:Animal; 
animal = new Owl(); 
animal.fly(); 

さらに、アニマルクラスは抽象クラスでなくてもよく、通常のクラスまたはインターフェイスでもかまいません。結果は同じになります。

私の質問はです:私のクラスが他のクラスのスーパーセットである場合、なぜtypescriptがそれをスローしますか?私は、この例では、オブジェクトがeat()またはsound()のようないくつかのプロパティを持つことをインターフェイスと型付けの主な考え方で保証していると思います。

私は何かが間違っている可能性がありますので、何らかの変数がいくつかの型になっている必要がありますが、サブクラスで追加のメソッドを使用できるようになりました。

+0

を使用してオフ最高ですあなたは正しく – Dummy

答えて

3

あなたは動物を定義したようにtypescriptですがanimal: Animal;

のための推論種類を実行しませんのでAnimalとして、Animalで定義されたメソッドとフィールドのみが使用可能になります。

強いタイピングが働く方法です。あなたはそれ上の任意のメソッドを呼び出すことができるようになります

animal 

または

animal : any 

いますが、型チェックを失う:あなたは、動物を宣言すると

回避策として、動物がOwlの場合は、キャストを使用してOwlを操作することができます。

タイプのアサーションは、「私は私がやっている 知って、私を信頼しています。」コンパイラに指示する方法です型アサーションは、他の言語でキャストタイプのようです が、の特別なチェックやリストラを実行しませんデータ。 ランタイムインパクトはなく、コンパイラによってのみ使用されます。 TypeScriptは、 が必要な特別なチェックをプログラマが実行したとみなします。

if (box.animal instanceof Owl){ 
    (box.animal as Owl).fly 
} 

しかし、より良い方法は、一般的なBoxを持っているだろう:

class Box<T extends Animal> implements BoxInterface { 

    animal: T 

    constructor(animal: T) { 
     this.animal = animal 
    } 

} 

今、あなたは書くことができます。いずれの場合で

let box = new Box<Owl>(new Owl()); 
box.animal.sound() 
box.animal.fly() 

を、IMSoPは非常によく言ったように: に固有のメソッドを適用する場合は、ある時点であなたが持っているものを知る必要があります。

+0

をOOPを理解していないが、アイデアは、私は、このオブジェクトの型は動物のものであろうだけを知っているが、私はそれはフクロウやヘビです見当がつかない。私は食べるような方法を共有するだけに興味があるので、エラーは出ませんが、フクロウが他のいくつかの追加プロパティを持っていればOKです。このコンセプトのポイントではないのですか? – Griva

+0

私は理解します。ジェネリックでは、この動作を得ることができます。私は更新しました。 – davidxxx

+0

これらのオブジェクトをいくつかのファクトリ/ビルダーから取得する場合、たとえば 'builder.createRandomAnimal();'汎用のものを使用できますか?私は後でこれがフクロウまたはヘビであると判断し、いくつかの追加メソッドを実行します。 – Griva

2

BoxにはAnimalが含まれていることが保証されているため、すべてがAnimalの場合はfly()です。

あなたが唱えられる(type assertOwlからBoxAnimal、およびその後は、それが飛ぶています

(box.animal as Owl).fly() 
1

基本クラス契約により、の最小のメソッドがすべてのサブタイプで使用できることが保証されていることは間違いありません。

ただし、TypeScriptは追加の制約を適用しています。が知っているメソッドのみを呼び出す必要があります。オブジェクトがある場合はが利用可能です。

この場合、コードbox.animal.fly();を書いている間は、あなたはAnimalです。したがって、すべて動物が持っているメソッドだけを呼び出す必要があります。

は、このチェックがなかった場合はどうなるかを考えてみましょう:

let animal:Animal; 
animal = new Snake(); 
animal.fly(); 

あなたは、実行時にエラーのいくつかの種類になるだろう。型チェッカーのアイデアは、あなたのためにこの可能性を見つけ、この意味で「安全」なコードを書くようにすることです。

0

これはOOP問題です。特定の型の変数を宣言し、それに値を代入すると、その値には実行時型と静的(コンパイル時)型の2種類があります。コンパイラによって考慮される型は、その変数(動物であり、Owlではないので、メソッドfly()を持つことはできません)に対して宣言された型です。これは、オーバーライドされたメソッドに意味を持ちます(言語仕様に応じて静的または動的情報によって解決できます)。詳細情報については

What is the difference between statically typed and dynamically typed languages? https://en.wikipedia.org/wiki/Multiple_dispatch

0

を見て他のすべての答えは有効です。 があなたの問題のため、あなたがジェネリックに

class Box<T extends Animal> { 
    constructor(public animal: T) { } 
} 

const box = new Box(new Owl()) 
box.animal.fly()