2016-09-24 46 views
0

我在打字稿2.0這樣的功能:打字稿2.0控制流分析和從未鍵入

function test(a:string) { 
    var b = typeof a === "function" ? [a] : a; 
} 

預期行爲: 類型的bstring。如果條件爲始終爲,則可能會發出警告。

實際行爲: 類型的bnever[] | string

這是爲什麼?

+0

我不知道這裏是否有一個非常有趣的答案,只是'tsc'很聰明,但不*聰明。 –

+0

似乎編譯器足夠聰明。返回一個「從不」意味着你的預期。唯一不太清楚的是爲什麼它返回'never []'而不是'never',但即使這樣也可以合理化,因爲如果條件成立,你期望得到一個數組,但是因爲它從來就不是這樣仍然得到陣列。 –

回答

1

剛剛玩過這個,考慮一下,實際上TS編譯器非常聰明。 TSC非常瞭解操作員的類型,並在流量類型分析中對其進行跟蹤。

關於TS的一個非常酷的事情是,不要強加高眉,高牧,OO-like(想象多級多級類層次結構),逆變和協變類型(想想斯卡拉[+T][-T]聰明但複雜),TSC只是試圖根據他們所處的美麗混亂來模擬JS類型,並且儘可能使用最簡單的機器來完成。

TS的類型系統是一種金蝶類型系統:不是太多,也不是太少;正好。

因此,我們來分析一下爲什麼要回答你的問題「爲什麼?」。

三元表達式condition ? X : Y的類型是typeof(X)typeof(Y)的聯合。這是因爲,在一般情況下,當條件爲真時,X會被返回。&其類型爲typeof(X),否則Y會返回,否則返回&其類型爲typeof(Y),因此它必須是其中一個。每個JS程序員都會在她/她的腦海中進行這種類型的流分析,因爲vanilla JS沒有任何正式的寫入類型的語法。但是TypeScript,FaceBook的Flow &其他編譯到JS系統爲JS錶帶來了類型語法,所以現在我們可以將三元結構的類型識別爲typeof(X) | typeof(Y)

在你的例子中,X是[a],Y是字符串,所以編譯器試圖找出的類型是typeof([a])| typeof運算(a)中。 RHS很簡單:它只是string,因爲函數的論點是這樣說的。 LHS類型必須是數組類型,因爲[a]這樣說,所以它將以TS類型語法寫成X []。如果我們能弄清楚X是什麼。

對於LHS,編譯器首先推斷typeof(a)必須是Function,因爲條件如此。但函數的簽名說typeof(a)string。因此,在[a]的情況下,typeof(a)必須同時爲Function以及string。這聽起來有點量子(想想量子態),但它並不是真正致盲科學。它是一個簡單的連接或類型的交叉點(用於輸入AND運算符的大字),可以寫成(函數&字符串)。所以現在這個三元表達式的整體類型是(Function & string)[] | string

最後,編譯器知道所有函數值集合和所有字符串值集合的交集是空集合。因此,TSC進一步減少Function & stringnever,因爲該值可能「永遠不會發生」,這就是爲什麼在這個非常冗長的答案中,TSC表示類型爲never[] | string

但是,nevers數組永遠不會發生,這是另一組空值。這帶給我們你的預期行爲,b的類型只是string,這是一個微不足道的子集(與在相同集合中)到never[] | string。編譯器可以計算這個額外的步驟並進一步減少類型表達式。這是一個功能還是一個錯誤,取決於你是否認爲簡單是一個功能或其他!

與Nitzan的答案一致,never[]永遠不會發生,永遠不會發生,因此這些類型代表相同的一組值。 never[]可能更精確一些,因爲它告訴您可能返回的內容的形狀(它是容器),如果確實返回了任何內容。

另一方面,你的函數從來沒有拋出異常,所以說Nitzan認爲類型可能會減少到never | string,可能是錯誤的或誤導性的。 never | string是你會得到三元表達式類型:

condition ? throw Error("WTF") : "Ecma Scriptus MMXV"

我愛這些小的難題,如果蘋果的空籃子是一樣的橙子的空籃子經常在想。

乾杯。