簡體   English   中英

分配給 TypeScript 接口中的動態尋址屬性

[英]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();
    });
}

Typescript 操場

通過使用類型簽名(keyof FidelityCheckRow)[]您可以指定每個key可以是FidelityCheckRow的任何鍵,也可以是具有數字值的鍵。 如果沒有強制轉換,類型將是string[] ,這也不是您想要的,但是如果您使用as constkeys聲明為元組,則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()
    })
}

TypeScript操場

關於驗證密鑰:

由於我們使用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"'.

TypeScript操場

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM