網站搜尋

擴展索引型 TypeScript 介面


考慮一個簡單的索引介面:

interface FormData {
    [K: string]: string;
}

那個小傢伙運作得很好。但是,有一種情況下我希望允許一個屬性是一個字串陣列。

interface AcmeFormData extends FormData {
    foobar: string[];
}

Typescript 提出警告

類型為 'string[]' 的屬性 'foobar' 無法賦值給字串索引類型 'string'。

查看這些文件,似乎以下操作應該是可能的,但也會報錯。

interface FormData {
    [K: string]: string;
    foobar: string[];
}

應該注意的是,我想避免使用聯合類型([K: string]: string | string[];),因為99%的情況下,數據總是單一的字符串值,因此我想避免必須進行類型提示。

這有可能嗎?還是我在試圖濫用 Typescript?

答案#1

你可以使用交集來做到這一點,而不是使用 extends。例如:

interface FormData {
    [K: string]: string;
}

type AcmeFormData = FormData & { foobar: string[] };

declare const test: AcmeFormData;

test.foobar       // string[]
test.anythingelse // string

然而,這確實會導致一些你需要小心的問題,因為現在索引簽名不再準確。因此,當 TypeScript 使用該簽名推斷某些內容時,你需要意識到它可能是錯誤的:

for (let key in test) {
    // val is inferred to have type string, but be careful!
    // In truth, val will be a string[] for the 'foobar' key,
    // but typescript is no longer aware of that. So this will
    // create a runtime error, but compiles without problems!

    const val = test[key].toLowerCase();
}

答案#2

這個方法無法運作的原因是因為 [K: string]: string 表示介面中 每個鍵 的值都必須是字串,而 foobar 包含在每個鍵中。我建議改成這樣做:

interface FormData {
  fields: { [field: string]: string }
  somethingElse: string[]
}