[英]Assigning to a dynamically addressed property in TypeScript interface
我正在嘗試從一個變量動態訪問 object 屬性,該變量是keyof
變量類型的鍵。 示例(與TypeScript 游樂場鏈接相同):
interface FidelityCheckRow {
P1: number;
P2: string;
P3: string;
}
const keys: (keyof FidelityCheckRow)[] = ['P2', 'P3'];
function test(a: FidelityCheckRow) {
keys.forEach(key => {
a[key] = a[key]?.toString()?.trim()
})
}
當基本 object 接口包含不同類型的屬性(不是所有字符串)時,我收到以下錯誤:
Type 'string' is not assignable to type 'never'.(2322)
什么是非法的? 我怎樣才能讓 TypeScript 明白我的意圖?
PS 實際上我將迭代string
屬性的子集,也許這些信息可以幫助找出正確的方法。
是的,首先提取類型的字符串屬性,然后在 forEach typescript 中檢測屬性字符串。
例如:
interface FidelityCheckRow {
P1: number;
P2: string;
P3: string;
}
type ExtractStringPropertyNames<T> = {
[K in keyof T]: T[K] extends string ? K : never
}[keyof T]
type STRING_KEYS = ExtractStringPropertyNames<FidelityCheckRow>
const keys: STRING_KEYS[] = ['P2', 'P3'];
function tests(a: FidelityCheckRow) {
keys.forEach(key => {
a[key] = a[key].toString().trim();
});
}
通過使用類型簽名(keyof FidelityCheckRow)[]
您可以指定每個key
可以是FidelityCheckRow
的任何鍵,也可以是具有數字值的鍵。 如果沒有強制轉換,類型將是string[]
,這也不是您想要的,但是如果您使用as const
將keys
聲明為元組,則key
的類型將正確縮小:
interface FidelityCheckRow {
P1: number;
P2: string;
P3: string;
}
const keys = ['P2', 'P3'] as const
function test(a: FidelityCheckRow) {
keys.forEach(key => {
a[key] = a[key]?.toString()?.trim()
})
}
關於驗證密鑰:
由於我們使用keys
作為元組來保留確切的文字類型,因此我們不能使用類型簽名來驗證這些鍵,因為生成的類型將不再是特定的。 不正確的鍵會在使用時觸發錯誤(例如在a[key]
處)。
有一些變通方法可以確保keys
只有有效鍵,例如通過創建一個泛型類型,將其參數限制為一組有效鍵:
type AssertKeys<K extends ReadonlyArray<keyof FidelityCheckRow>> = never
您可以通過在您的鍵定義附近放置一個虛擬Assertion
類型並將其傳遞給鍵元組的類型來使用它:
const badKeys = ['P2', 'P3', 'P4'] as const
type Assertion = AssertKeys<typeof badKeys>
// ERROR: ... Type '"P4"' is not assignable to type 'keyof FidelityCheckRow'.
另一種選擇是使用構造函數 function 來創建密鑰,這只是一個身份 function ,它將其參數限制為有效的密鑰元組:
const mkKeys = (ks: ReadonlyArray<keyof FidelityCheckRow>) => ks
如果您使用mkKeys
創建鍵元組,任何無效鍵都將被標記:
const mkKeys = <K extends ReadonlyArray<keyof FidelityCheckRow>>(ks: K) => ks
const goodKeys = mkKeys(['P2', 'P3']) // No error
const badKeys = mkKeys(['P2', 'P3', 'P4'])
// ERROR: Type '"P4"' is not assignable to type 'keyof FidelityCheckRow'.
當我們這樣做的時候,我們不妨使用 object 類型和所需的值類型對構造函數進行參數化,因此您可以將它用於FidelityCheckRow
以外的其他接口,以及string
以外的其他值類型:
type FilterKeysByValue<T, V> = keyof {
[K in keyof T as T[K] extends V ? K : never]: never
}
const mkKeys = <T, V>(ks: ReadonlyArray<FilterKeysByValue<T, V>>) => ks
錯誤消息的描述性稍差,但使用顯式類型參數,只需一個波浪線可能就足以了解問題所在:
const goodKeys = mkKeys<FidelityCheckRow, string>(['P2', 'P3']) // No error
const badKeys1 = mkKeys<FidelityCheckRow, string>(['P1', 'P2', 'P3'])
// ERROR: Type '"P1"' is not assignable to type '"P2" | "P3"'.
const badKeys2 = mkKeys<FidelityCheckRow, number>(['P1', 'P2', 'P3'])
// ERROR: Type '"P2"' is not assignable to type '"P1"'.
// ERROR: Type '"P3"' is not assignable to type '"P1"'.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.