2017-09-13 77 views
2

我目前正在學習結構分型。我對這樣的想法持懷疑態度,認爲兩種類型被認爲是相同的,只是因爲它們碰巧有一部分共同的結構。這感覺很像靜態鴨子打字,它完全忽略了類型的語義層次。所以我把在普通對象的流動的結構打字定睛一看,也遇到以下行爲:流的結構子類型是否「忘記」特定的子類型屬性?

const o:{} = {foo: true}; 
o.foo; // type error 

{}是一種結構類型和所有普通對象的超類型。因此,我可以用它註釋o,因爲{foo: true}{}的結構子類型。但是,當我嘗試訪問現有的foo屬性時,此操作不會進行類型檢查。這很奇怪,因爲AFAIK結構子類型通常可以包含特定屬性,只要它還包含其超類型的所有必需屬性即可。

看起來流程的結構分型算法偶爾會忘記特定於某個子類型的屬性。這種行爲是有意的還是我只是遇到了邊緣案例?

+1

你能澄清你的意思嗎?通過聲明類型':{}',你已經明確地刪除了它的類型信息,就像你做了'Animal foo = new Cat()','foo'不知道它是'Cat',它只知道它是一個'動物'。 – loganfsmyth

+0

@loganfsmyth'{}'只是沒有任何結構的最一般的普通對象類型。這當然是無用的。問題是,如果我在這個邊緣案例中觀察到的行爲是更深層次的問題的一部分,這個問題是特定於子類型的。 – ftor

+1

我想澄清的是,如果你認爲這是一個邊緣案例,那麼它會是一個問題呢?在JavaScript作爲一種無類型語言的情況下,絕對有些情況下你會擁有一個對象,而對它所擁有的屬性一無所知。爲了得到'foo',你可以這樣做:if(typeof o.foo ===「boolean」){/ *用屬性作爲布爾值* /}來操作,它會很好用。 – loganfsmyth

回答

3

您所描述的總體問題是從子類型轉換爲超類型的事實。通過執行轉換,您明確告訴編譯器放棄關於給定對象的信息。

舉例來說,即使沒有結構性打字,如果你這樣做

class Animal {} 

class Cat extends Animal { 
    foo: bool = true; 
} 

const c: Animal = new Cat(); 

console.log(c.foo); 

On flow.org/try

它沒有類型檢查出於同樣的原因。在你的例子中,你明確地告訴編譯器「考慮o的類型爲{}」,就像我在我的例子中所說的「考慮c的類型爲Animal」。因此,編譯器明確被告知忘記它正在使用Cat,因此它忘記了該對象具有.foo屬性。

看起來流程的結構子類型化算法偶爾會忘記特定於某個子類型的屬性。這種行爲是有意的還是我只是遇到了邊緣案例?

所以要回答這個問題,它不會「偶爾」這樣做,它完全是在您告訴它這樣做的時候做到的。行爲是絕對有意的。

這很奇怪,因爲AFAIK結構子類型通常可以包含特定屬性,只要它還包含其超類型的所有必需屬性即可。

對象確實包含了屬性,這是100%的罰款,但你已經明確的價值轉換爲一超擦除的信息。

+0

這確實不是我最好的問題之一。感謝您花時間回答它!所以真正的問題是當沒有任何明確的註釋時流是如何表現的,但是類型必須被推斷出來,因爲一個對象是由更復雜的組合中的函數返回的。有沒有信息丟失?相關:[包含規則](https://news.ycombinator.com/item?id=13047934) – ftor

+1

我覺得我需要一個明確的例子,但據我所知,不應該有任何信息丟失類型推斷。 – loganfsmyth

相關問題