![](/img/trans.png)
[英]Why does typescript generics infer different types if array member is wrapped?
[英]Why Typescript can get the exact value when giving a Generics that extends types
我只有字符串[]
function getResult<T>(...v: T[]) {
return v
}
const str = getResult('str', 'str2') // const str: string[]
// or even
const str = getResult<string>('str' as const, 'str2') // const str: string[]
// for stirng
function getResultByExtendsString<T extends string>(...v: T[]) {
return v
}
const str2 = getResultByExtendsString('str', 'str2') // const str2: ("str" | "str2")[]
// for number
function getResultByExtendsNumber<T extends number>(...v: T[]) {
return v
}
const num2 = getResultByExtendsNumber(123, 456) // const num2: (123 | 456)[]
但是如果我刪除 P、Q 的擴展,它不會得到值,而是它的類型
type Types = string | number
function getAllResults<P extends Types, Q extends Types>(p: P, v: Q): (P | Q)[] {
return [p, v]
}
const res = getAllResults('str', 123) // const res: ("str" | 123)[]
謝謝。 從ts背景看
這可以通過編譯器的“上下文類型”功能來確定。 即使您在等式的一側(即函數)只有類型,TypeScript 編譯器也可以確定類型。 通用類 | 功能 | 如果數據類型未知或“復雜”,則變量通常用作“復雜”類型。
資源:
https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html#types-by-inference
https://www.typescriptlang.org/docs/handbook/functions.html#inferring-the-types
這是microsoft/TypeScript#10676 “始終使用文字類型”的結果。 一般來說,編譯器最初總是為字符串、數字或布爾值推斷最窄的文字類型。 所以"str"
被視為類型"str"
。
但是,編譯器會經常(但不總是)擴展類型,這取決於它的使用方式。 所以有時類型"str"
被擴展為string
; 而其他時候它會保持"str"
。 上面鏈接的拉取請求經歷了許多不同的情況,其中一種行為或另一種行為發生(例如, const str = "str";
未加寬,但let str = "str"
加寬),並且您可以粗略地說類型被加寬,除非編譯器知道您期望更窄的類型。
但特別是,與此問題相關的啟發式方法是當您調用泛型函數時編譯器如何推斷類型參數:
在調用表達式的類型參數推斷期間,為類型參數 T 推斷的類型擴展為其擴展的文字類型,如果:
- 對 T 的所有推斷都是對特定參數類型中 T 的頂級出現進行的,並且
- T 沒有約束或其約束不包括原始類型或文字類型,並且
- T 在推理過程中是固定的,或者 T 不會出現在返回類型的頂層。
因此,如果T
沒有約束,如getResult<T>(...)
,或者如果約束不包括原始類型或文字類型,如getSomethingElse<T extends Date>(...)
, T
將被加寬。 因此,對於那些調用,您將獲得string
或number
而不是字符串或數字文字。
但是在存在包含原始類型的約束的情況下,例如getResultByExtendsString<T extends string>(...)
或getResultByExtendsNumber<T extends number>(...)
,甚至getAllResults<P extends Types, Q extends Types>(...)
(因為Types
包括string
和number
),類型沒有加寬。 所以"str"
或123
將保持"str"
和123
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.