使用 TypeScript 鍵入物件時遇到問題
我宣告了一個由應用程式的某些檔案使用的型別:
type Category = "cat1"|"cat2"|"cat3"|"cat4"
我Category用來鍵入一個物件 & 一切正常使用:
const obj: {
[key in Category]: string
} = {---}
但是現在,我想添加 2 個不是Category物件上的值的鍵。我認為通過輸入這樣的物件會很容易:
const obj: {
customKey1: string
customKey2: string
[key in Category]: string
} = {---}
但是,TS 沒有按預期作業,而是發送 3 個錯誤:TS2464、TS1170 和 TS2693
A computed property name must be of type 'string', 'number', 'symbol' or 'any'. ts(2464)
'Category' only refers to a type, but is using as a value here. ts(2693)
A computed property name in a type template must refer to an expression whose type is a literal type or a 'unique symbol' type. ts(1170)
好吧……為什么?正如Category通過檔案共享的那樣,我不想通過添加這些僅在此處需要的自定義鍵來編輯它。我解決了這個問題,所以如果其他人也面臨這個問題,我會在下面給出一個解決方案,但有沒有人知道為什么我的第一個想法不能應用?
我不明白為什么[key in Category]: string單獨寫作會起作用,但如果添加另一個鍵會引發錯誤。
uj5u.com熱心網友回復:
對于那些不需要解釋而只需要可用解決方案的人,這是我的:
type Keys = { [key in Category]: string }
interface Obj extends Keys {
customKey1: string
customKey2: string
}
const obj: Obj = {---}
它作業正常。
uj5u.com熱心網友回復:
該{[K in XXX]: YYY}語法是一個映射型別,其遍歷keylike型表達的并集成員的特殊物件型別XXX,并使用型別引數K為每一個內部YYY型別的表達。(注意,K代表型別,而不是一個屬性鍵的值,所以按照慣例,我們用大寫字符出現)。可以使用K內部YYY表達,使得每個鍵K中XXX可以有不同的值的型別,比如{[K in "a" | "b"]: K}是相當于{a: "a", b: "b"}。 映射型別語法不可推廣或可擴展;你不能把其他屬性放在那里{[K in XXX]: YYY; somethingElse: string},也不能把它們放在里面interface宣告,或者用它做任何其他事情。這樣做是一個語法錯誤。在某種意義上說,大括號{ ... }是語法映射型別的一部分,并且,即使他們看起來像其他物件型別的大括號,他們不采取行動像他們一樣。
重要的是不要混淆這句法與外觀類似的是非常重要的{[k: XXX]: YYY}語法指數的簽名。映射型別使用in關鍵字,而索引簽名不使用,并且需要一個虛擬鍵名識別符號(k在此處的示例中)。虛擬鍵名只存在于鍵內部,不能在YYY運算式中使用,所以不允許你為 中的不同鍵分配不同的值XXX;索引簽名不會XXX以任何方式迭代內部的鍵。作為signatures,索引簽名可以與其他屬性一起用于任何物件型別,例如{[k: XXX]: YYY; somethingElse: string},只要其他屬性不與索引簽名沖突。它們可以包含在interface宣告。花括號不是索引簽名語法的一部分。
因此,您的問題是:為什么不能向映射型別添加其他屬性?為什么映射型別中的大括號不能像在其他映射型別中那樣作業?
在microsoft/TypeScript#13573 上有一個問題詢問了這個確切的問題。不過,似乎沒有明確的答案。這似乎是一個意料之外的用例。有一段時間,microsoft/TypeScript#26797的拉取請求可能會合并到語言中,作為統一映射型別和索引簽名的一部分,但這從未發生過。一個相關的注釋在微軟/打字稿#45089由TS團隊成員解釋說,在這一點上是不可能的,任何事情都會在這里改變,因為它開辟了關于如何應對可能沖突的型別和問題仿制藥:
混合映射型別和屬性宣告有一些奇怪的含義,可以通過交集優雅地解決
我不會在這里明確地討論這些;您可以查看鏈接的問題以獲取更多資訊。
就目前而言,這就是“為什么會這樣”的答案。那么你能做些什么呢?上面的評論提到了交叉點;您可以通過交集將兩種物件型別的屬性合并在一起,因此{a: string} & {b: string}本質上與{a: string; b: string}. 因此,撰寫物件型別的一種方法是:
type MyObjType =
{ [K in Category]: string } &
{ customKey1: string, customKey2: string };
您不能直接使用交集作為介面型別,但您可以使用靜態已知鍵使介面擴展其他命名型別。您具有靜態已知的鍵,因為它不是通用的,但它不是命名型別。您可以自己命名,然后擴展它:{[K in Category]: string}Category
type CategoryProps = { [K in Category]: string };
interface MyObjType extends CategoryProps {
customKey1: string
customKey2: string
}
或者,你可以使用的Record<K, V>實用型和擴展,而無需宣布一個新的名字:
interface MyObjType extends Record<Category, string> {
customKey1: string
customKey2: string
}
最后,你總是可以反其道而行之,并為所有鍵使用映射型別,而不是嘗試單獨添加它們:
type MyObjType =
{ [K in Category | "customKey1" | "customKey2"]: string };
Playground 鏈接到代碼
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/326529.html
標籤:打字稿
