網站搜尋

javascript - 在 TypeScript 中定義物件並訪問其值的最佳方式是什麼?


我有一個格式的物件

export const IconSizeMap = {
  'extra-small': '0.75rem',
  small: '1rem',
  medium: '1.5rem',
  large: '2rem',
  'extra-large': '4rem'
};

作為 TypeScript 新手,我無法理解錯誤是什麼

它出錯了

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ 'extra-small': string; small: string; medium: string; large: string; 'extra-large': string; }'.
  No index signature with a parameter of type 'string' was found on type '{ 'extra-small': string; small: string; medium: string; large: string; 'extra-large': string; }'.ts(7053)

當我嘗試使用

IconSizeMap[size]

我該如何解決這個錯誤?

答案#1

你會收到這個錯誤是因為你的 tsconfig.json 啟用了 "noImplicitAny": true。這意味著 TypeScript 會尋找並告訴你那些你使用了類型未知的值的地方,而你並未明確告訴它應該是什麼類型。

你消除它的解決方法是:

  • 在配置中禁用 noImplicitAny(但我猜它存在是有原因的,所以我不建議這麼做)
  • 告訴 TypeScript 你正在使用的會導致錯誤的東西的類型。

在這裡,TypeScript 辨識了你定義的每個 5 個鍵(extra-small、small、medium、large 和 extra-large),因為你給它們指派了一個 string 值,所以它可以判斷它們是字串。然而,只有這 5 個 string 是鍵。

當你使用「通用」的 string 來存取你的物件,例如我假設你的 size 是這樣,你就無法確定它是否對應到這五個鍵之一。因此,TypeScript 會警告你這一點。

一種解決方法是告訴編譯器你對自己的操作很有把握,並更精確地指定 size 的類型。例如:

export const IconSizeMap = {
  'extra-small': '0.75rem',
  small: '1rem',
  medium: '1.5rem',
  large: '2rem',
  'extra-large': '4rem'
};

let size: keyof typeof IconSizeMap; // Means "I'm sure that size is one of those strings
size = "small";

console.log(IconSizeMap[size]);

遊樂場連結

答案#2

IconSizeMap[size] 正在嘗試將一個字串作為索引用於一個沒有定義字串索引的物件,這就是你收到該錯誤的原因。

您的選項是:

  1. 為該對象添加一個字串索引簽名,或者

  2. 不要使用一般字串來索引物件

你做什麼取決於你的使用案例。索引簽名意味著 TypeScript 無法主動幫你檢查 size 是否與對象上的某個屬性匹配。但僅使用特定的屬性名稱意味著如果你的起點是一個可能具有任何值的字符串,你需要在多個地方列出那些屬性名稱。

這裡有一個 #1 的例子:

export const IconSizeMap: {[key: string]: string} = {
// −−−−−−−−−−−−−−−−−−−−−^^^^^^^^^^^^^^^^^^^^^^^^^
  'extra-small': '0.75rem',
  small: '1rem',
  medium: '1.5rem',
  large: '2rem',
  'extra-large': '4rem'
};

遊樂場連結

這裡是 #2 的例子:

function getIconSize(size: string) {
    switch (size) {
        case 'extra-small':
            return IconSizeMap['extra-small'];
        case 'small':
            return IconSizeMap.small;
        case 'medium':
            return IconSizeMap.medium;
        case 'large':
            return IconSizeMap.large;
        case 'extra-large':
            return IconSizeMap['extra-large'];
        default:
            throw new Error(`Invalid 'size' for IconSizeMap: ${size}`);
    }
}

注意我們在訪問物件時使用特定的字串字面值,而不只是任何字串。

遊樂場連結