問題的TS游樂場
function callStringFunction(callback: (s: string) => void) {
callback("unknown string inputted by user");
}
function callNumberFunction(callback: (n: number) => void) {
callback(4); // unknown number inputted by user
}
function genericFunction<T extends string | number>(value: T, genericCallback: (newValue: T) => void) {
if (typeof value === "string") {
console.log(value); // T is known to be a string here
callStringFunction(genericCallback); // But this throws an error: (newValue: T) => void not assignable to (s: string) => void
}
else {
console.log(value); // T is known to be a number here
callNumberFunction(genericCallback); // But this throws an error: (newValue: T) => void not assignable to (n: number) => void
}
}
我怎么能做到這一點而不訴諸:callNumberFunction(cb as (n: number) => void)
既然value已經檢查了 for 的型別,那么 TypeScript 不應該也知道回呼型別嗎?
uj5u.com熱心網友回復:
不幸的是,TypeScript 編譯器無法理解您在這里所做的事情。當您檢查typeof value === "string"時,編譯器將其視為一種型別保護value,從縮小T到string或number。但它對縮小型別引數T本身沒有任何作用。
您希望編譯器可以看到typeof value === "string"和value: T一起縮小T范圍T extends string | number,T extends string或者T extends number可能只是特定string的和number型別。這不會發生。 T停留T在整個函式中,因此callStringFunction(genericCallback)不能被接受。編譯器仍然認為這T可能是 string | number.
GitHub 中有開放的功能請求以某種方式改善這種情況;例如,參見microsoft/TypeScript#33014。但是,還沒有實施任何東西,部分原因是一些“明顯的”實施會很快導致不健全。
例如,如果我有function f<T extends string | number>(value1: T, value2: T): void;,我不能說value1作為 astring意味著value2也是 a string。畢竟,可能value1和value2are both string | number,就像在 call 中一樣f(Math.random()<0.99 ? "" : 123, 123);。有 99% 的機會value1是一段string時間value2是一個number. 所以任何處理這個問題的代碼都需要仔細考慮。
此外,我想不出一種重構代碼的好方法,以便編譯器可以安全地看到您正在做的事情。型別string和number不被視為可區分屬性型別,因此我無法將 args 串列重寫genericFunction()為可區分的 union。只有當你傳入一個像function genericFunction<K extends "str" | "num">(type: K, val: Val[K], cb: (x: Val[K])=>void): void;. 在這種情況下,您可以檢查type,然后編譯器會縮小val并cb合并在一起。但這不是你所擁有的,所以它不是一個直接的重構。
現在我想說最好的方法是使用型別斷言來告訴編譯器你知道你在做什么。val as Type在您確定val確實是型別Type但編譯器不能的情況下撰寫是合理的:
function genericFunction<T extends string | number>(
value: T, genericCallback: (newValue: T) => void
) {
if (typeof value === "string") {
console.log(value); // T is known to be a string here
callStringFunction(genericCallback as (newValue: string) => void);
}
else {
console.log(value); // T is known to be a number here
callNumberFunction(genericCallback as (newValue: number) => void);
}
}
這修復了錯誤,但將確保型別安全的負擔放在了您身上。這不是很好,但這是我目前能弄清楚的最好方法,無需重構為明顯不同的演算法。那好吧!
Playground 代碼鏈接
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/481656.html
標籤:javascript 打字稿
上一篇:替換網頁輸入框中的文本
下一篇:如何將坐標陣列中的每個值相乘
