假設我有function foo(args) {...}
,其中args
是一個二元組數組,這樣元組中的條目是相同類型的(即[T,T]
),但是跨元組的條目可能任意變化(即[[T,T], [U,U ],[V,V]]
)。例如:
foo([ [1, 3], ["hello", "world"], [true, true], [2, 7] ]) // no error
我應該如何輸入foo
的args
參數,以便元組中的不匹配類型引發編譯時類型錯誤?例如:
foo([ [1, 3], ["hello", 5], // type error here [true, true], [2, 7n] // type error here ])
如果無法內聯顯示類型錯誤,則使整個函數呼叫錯誤也是可以接受的。
附錄:是否可以使用[SomeType
類型的2 元組(即第二個條目的類型應與第一個),但T仍然可以在元組之間變化[[SomeType
?
foo([ [{value: 1}, 3], [{value: "hello"}, 5], // type error here [{value: true}, true], [{value: 2}, 7n] // type error here ])
我認為您可以透過為
row
建立一個類型來簡單地實現此目的,該類型將接受string
、number
或布爾值。型別 Row = string[] |布林值[] |數字[]
現在,我們可以為
foo
函數的args
參數指派此類型。使用此類型定義,如果您向
foo
提供一個參數,其中行中元素的類型不匹配,Typescript 將引發錯誤。這裡是遊樂場
連結代码>
.為了實現這一點,我們需要使用泛型陣列和映射類型來映射陣列的元素。由於我們知道該數組應該是長度為 2 的元組數組,因此我們將推斷元組中第一項的泛型參數,並使第二項具有相同類型。要取得泛型參數的類型,我們需要使用推斷關鍵字。請注意,我們需要確切地知道(或至少是具有相似形狀的類型)用於使其工作的泛型類型,在我們的例子中是
Variable
:看起來似乎就是全部,但是讓我們看看以下數組的類型:
如您所見,該類型與我們在 arr 中的類型不完全相同。編譯器擴展了類型以確保我們可以改變數組元素。為了讓編譯器知道該陣列是唯讀的,我們需要使用const 斷言:
現在看起來不錯,這意味著我們需要將傳遞給
foo
的數組設定為只讀`,並且由於只讀取組是我們將得到的可變數組的超集如果我們嘗試將只讀取組傳遞給數組,則會出現錯誤:因此,我們將
foo
中的所有陣列類型更新為唯讀。請注意,由於我們的數組是二維的,因此內部數組也將是唯讀的,並且數組的約束應該是只讀數組的只讀數組:測試:
但是,我們仍然存在一些問題。例如,如果元組中的第一個元素是
Variable
,則表示第二個參數也應該是7
,而不是任何數字,如果這是一個問題我們需要取得7
的原語,即數字。這可以使用ToPrimitive來自我的type-samurai開源專案的實用程式類型: p>更新功能:
另一個問題是,如果在我們目前的
foo
實作中推斷的類型是number[]
,我們將不會允許只讀取組:修復非常簡單,我們將檢查推斷的類型是否是某個數組,然後獲取其元素類型並將 readonly ElemenType[] 作為元組中的第二個參數:
測試:
令人煩惱的部分是我們需要在任何地方使用
const 斷言
。在 Typescript5.0
中,const 類型參數,這樣我們就可以避免const 斷言
:不幸的是,我們無法使用它們,因為我們對參數進行了一些操作,而不是直接將
T
作為類型分配給它:總之,目前,
const 斷言
是確保其按預期工作的唯一方法。連結到遊樂場
#