2016-09-09 58 views
2

在下面的示例中,Promise::then訪問者函數f有望收到Example。如果我顯式傳遞一個缺少屬性的格式錯誤的對象,我會得到一個類型錯誤。爲什麼沒有在打字稿中檢查頭等功能?

但如果我只是傳遞函數f.then(f)我沒有得到任何類型的錯誤,即使打字稿知道在Promise<T>T的類型不是Example

interface Example { 
    id: number 
    age: number 
} 

interface Promise <T> { 
    then <U> (f: (a: T) => U) : Promise<U> 
} 

function f(s:Example){ 
    return s.age 
} 

var p : Promise<{ id: number }> 

p.then(f) // no type error (bad) 

p.then(function(a){ 
    f(a) // type error (good) 
}) 

我想知道爲什麼會發生這種情況,但也有技術來緩解Typescript中的寬容類型檢查。

如果雙變量解釋了這種現象,那麼當明確應用f時爲什麼會出現類型錯誤?爲什麼他們的第一類函數與顯式應用程序有不同的規則?

+0

可能的重複:http://stackoverflow.com/questions/38699449/compatible-types-in-functions/38700451#38700451。另請參見[類型檢查不穩定性:在TypeScript團隊/社區中標準化處理此類問題](https://github.com/Microsoft/TypeScript/issues/9825) – artem

+0

@artem我不認爲這是由於雙變量。但我可能是錯的。 –

回答

2

這裏是什麼,我認爲正在發生的事情:

p.then(f) // no type error (bad) 
  • T這裏是{ id: number }
  • then()聲明採取型{id: number} => U
  • f的的參數類型Example => number
  • Example是分配給{id: number},所以f與參數類型的then()由於bivariance

兼容讓我再補充一個例子:

p.then(function(a : Example){ 
    f(a) 
}) 

它還編譯沒有錯誤,出於同樣的原因:

  • 論據then()的類型爲Example => number

現在,爲什麼下面不能編譯?

p.then(function(a){ 
    f(a) // type error (good) 
}) 
  • 我想這a被推斷爲有型{id: number}(因爲這樣做最簡單的事情就是要把它是Tp聲明)
  • 所以f被稱爲與此處不兼容的參數
  • 因爲{id: number}不能轉讓給Examplef需要(年齡是missin G)。

請注意,錯誤不是關於then()的參數,而是關於f()的參數。

現在,對於問題的第二部分:

技術來減輕許可類型中打字稿檢查。

如果您需要正確的類型檢查,只要「可用」類型檢測仍然是其明確的設計目標之一,那麼IMO Typescript就不是一種選擇。我聽說Scala,Haskell和OCaml現在都有針對javacsript的編譯器(但我不知道它們有多可用)。

而問題的第三部分:

爲什麼是一等功能VS明確 應用各自不同的規則?

因爲在第一種情況下的參數是一個函數,和在第二種情況下(其不編譯)參數已經推導出類型{id : number},這是不是一個函數。雙變量是一個臨時規則,僅當需要確定一個函數類型是否與另一個函數類型兼容時才適用。第一種情況編譯,因爲一旦它看到根據規則then()參數是好的,它不會下降到then()實現來檢查它將如何在那裏實際工作。這是什麼使它不健全。

+0

您的回答很有幫助,但我仍不明白爲什麼雙差異更適合第一類功能。如果雙變量解釋了這種現象,那麼對於顯式應用程序應該沒有類型錯誤,應該應用相同的規則。 問題Typescript的泛型在第一類函數中無法推斷結構嗎? –

+0

我添加了另一部分答案試圖解釋它。錯誤是由不正確的參數類型引起的,因爲參數不是函數,所以雙變量不適用。 – artem