網站搜尋

如何在 TypeScript 中輸入帶有索引簽名和動態變量的物件?


我剛接觸 TypeScript,試過各種方式來定義這個類型,但在索引簽名上遇到問題。這個介面應該長什麼樣子?

interface MyConfig {
...
}

// someVar can be any string
let someVar = "dynamicKey";

// the structure of the object cannot change
const config: MyConfig = {
  myObj: {
    [someVar]: {
      firstProp: 'some text',
      secondProp: 'some text',
    },
    thirdProp: 'some text',
  },
};


答案#1

如果你知道 someVar 變數的確切值,你可以有一個嚴格的介面,如下所示:

interface MyConfig {
    myObj: {
        SomeKey: {
            firstProp: string
            secondProp: string
        },
        thirdProp: string
    }
}

然後你可以使用:

const someVar = "SomeKey";

const config: MyConfig = {
    myObj: {
        [someVar]: {
            firstProp: 'some text',
            secondProp: 'some text',
        },
        thirdProp: 'some text',
    },
};

但如果你希望 someVar 是動態的,這有點棘手。對此,我建議你將動態部分移到一個單獨的區塊,這樣你就可以使用:

interface MyConfig {
    myObj: {
        dynamic: {
            [key: string]: {
                firstProp: string
                secondProp: string
            }
        },
        thirdProp: string
    }
}

const someVar = "SomeKey";
const config: MyConfig = {
    myObj: {
        dynamic: {
            [someVar]: {
                firstProp: 'some text',
                secondProp: 'some text',
            },
        },
        thirdProp: 'some text',
    },
};

最後,如果你有動態的 someVar 並且無法更改資料結構,你可以使用以下方式:

interface MyConfig {
    myObj: ({
        [key: string]: {
            firstProp: string
            secondProp: string
        } | string
    } & {
        thirdProp: string
    })
}
const someVar: string = "SomeKey";

const config: MyConfig = {
    myObj: {
        [someVar]: {
            firstProp: 'some text',
            secondProp: 'some text',
        },
        thirdProp: 'some text',
    },
};

// String
console.log(config.myObj.thirdProp.trim())

// Error, union string | object
console.log(config.myObj.abc.firstProp)

if (typeof config.myObj.abc === 'object') {
    // string
    console.log(config.myObj.thirdProp.trim())
    // string
    console.log(config.myObj.abc.firstProp.trim())
}

在這個範例中,我們使用 TypeScript 的索引簽名並指定已知屬性。你也可以注意到一件奇怪的事——索引簽名有聯合類型 object | string。這是由於 TypeScript 的限制:

一旦你有了一個字串索引簽名,所有明確的成員也必須符合該索引簽名。這是為了提供安全性,以確保任何字串存取都會得到相同的結果。

參考:如何將已聲明的介面屬性與自訂索引簽名結合