2017-01-10 94 views
1

我有一個基本的傳承,像這樣:Typescript不能識別父類的屬性?

export abstract class Animal 
{ 
    constructor() { 

    } 

    makeSound() { 
     alert(this.sound); 
    } 
} 

export class Dog extends Animal 
{ 
    public sound: string = "Woof!"; 

    constructor() { 
     super(); 
    } 
} 

const dog = new Dog; 
dog.makeSound(); // Woof! 

我有一個問題,試圖讓上面的代碼工作。 Property prop does not exist on type A。然而,它確實存在於B上,並且由於它是公開的,所以A應該能夠通過this.prop達到道具。

我試過如下:

  • 同上 - 它不會編譯。 (屬性類型不存在於類型A上)
  • 如果我將public prop: any;添加到A,則prop將變爲undefined而不是Hello world
  • 如果我將public abstract prop: any;添加到A,則會發生同樣的情況。

通過使用抽象類的繼承的全部點是分享this範圍。

如何正確使用Typescript?

+0

不,這是自上而下的。一個蘋果(B)是一個水果(A),但一個水果不是蘋果。 繼承添加或更改行爲。你的B向A添加了一個屬性。所以很明顯A沒有它。 – chris01

+0

@chris謹慎闡述? – Aris

+2

你假設A的任何實例也是B的一個實例。不是這樣的:'C類擴展A {}'定義了一個擴展A的類,並且沒有任何屬性。 –

回答

4

我同意JB Nizet。但是您也可以將sound定義爲抽象屬性。這樣,你的基類知道sound,所有的擴展類必須實現抽象屬性sound

export abstract class Animal 
{ 
    abstract sound: string; // Only change here, now your code works 
    constructor() { 

    } 

    makeSound() { 
     alert(this.sound); 
    } 
} 

export class Dog extends Animal { 
    public sound: string = "Woof!"; 

    constructor() { 
     super(); 
    } 
} 

const dog = new Dog; 
dog.makeSound(); // Woof! 

定義抽象性與TS 2.0傳來的能力:https://github.com/Microsoft/TypeScript/issues/4669

更新

這個方法經驗豐富的問題​​,請參閱註釋,抽象屬性用於抽象基類的構造函數中。這是行不通的,因爲屬性被賦值了之後派生類的第一個的初始值。

對於這個問題,有一個github issue,其中解決方案是簡單地在抽象類的構造函數中訪問抽象屬性時出錯。

+0

亞歷克斯,當我嘗試使用抽象關鍵字方法時,聲音是'未定義的,所以它沒有讀取擴展類的值,正如我在我的問題中提到的。我會給這個試試看,很快就會通知你。編輯:是的,當我做'console.log(this.sound)'時,它輸出'undefined'。我在打字機'2.1.4'上。 – Aris

+0

@IcarusCocksson在這裏工作得很好:http://plnkr.co/edit/wRwff7MrFazrjYQHKmFI?p=preview –

+0

@JBNizet @Alex奇怪的是,它不適合我。如果你想看一下,我把提交到我的倉庫中:https://github.com/Aristona/Phaser.Adventure-Capitalist/tree/master/src/Shop - 這是抽象類,第50-55行是在那裏我定義了抽象屬性。 Shops文件夾中的所有類都擴展Shop,並自定義這些屬性。當我運行它時,它們都變成了「未定義」。 (Shop.ts中第50行和第55行之間的所有內容)。有任何想法嗎? – Aris

1

這裏是你如何定義你的兩個類:

export abstract class Animal { 

    protected constructor(public sound: string) { 
    } 

    makeSound() { 
    alert(this.sound); 
    } 
} 

export class Dog extends Animal { 
    constructor() { 
    super('woof'); 
    } 
} 

把財產在動物類會告訴所有的動物都具有良好的編譯器。將聲音作爲超類構造函數的一個參數使其清楚地表明,所有的子類在構造實例時都必須指定它們的聲音。

還有其他可能的變化,但是如果超類需要訪問sound屬性或getSound()方法,那麼這個屬性/方法應該存在於基類中。

1

錯誤消息是完全正確的:prop不存在A,因爲它存在於B。你可能來自JavaScript,你所做的只是很好。 TypeScript和JavaScript之間的主要區別在於TypeScript是強類型的,JavaScript是弱類型的。這種差異需要改變你的想法。

在像JavaScript這樣的弱類型語言中,prop不存在於A中並不重要。類型在運行時解析,如果你的實際實例有prop,一切都會好的。在靜態(或強烈)類型的語言中,事物是不同的。類型在編譯時執行,如果A未定義prop,則不能使用它。這就是爲什麼強類型語言允許你定義抽象成員:使它們在基類中可訪問,但實際上定義了派生類中的rhem。

由於not all versions of TypeScript support abstract properties directly,這個解決方案應該在任何情況下工作:

export abstract class Animal 
{ 
    get sound(): string { return getSound(); } 
    protected abstract getSound(): string; 
    constructor() {} 
    makeSound(): void { 
     console.log(this.sound); 
    } 
} 

export class Dog extends Animal 
{ 
    protected getSound: string { return "Woof!"; } 

    constructor() { 
     super(); 
    } 
} 

const b = new B; 
B.makeSound(); 
+0

get/set語法是強制性的嗎?另外,下面的語法看起來有點奇怪。 'protected getProp:string {return「Hello world」; }'。爲什麼我們將類型定義爲字符串,但將對象文本與返回關鍵字放在一起? o_O – Aris

+0

@IcarusCocksson:'getProp'是一種方法,而不是屬性。獲取方法調用的語法是因爲至少早期版本的TypeScript不支持抽象屬性。因此使用getter並調用抽象方法。 – Sefe