Обработка «Элемент неявно имеет тип 'any', поскольку выражение типа 'string' не может использоваться для индексации типа» - PullRequest
0 голосов
/ 25 мая 2020

Следующий код:

type ConfigValue = {
    title: string;
}

const enum ConfigKey {
    ConfigA = 'config-a',
    ConfigB = 'config-b'
}

// For each ConfigKey there must exist a record so I can't type it as Record<string, ConfigValue>. Doing config[ConfigKey.ConfigA] should be a safe action.
const config: Record<ConfigKey, ConfigValue> = {
    [ConfigKey.ConfigA]: {
        title: 'Config a title'
    },
    [ConfigKey.ConfigB]: {
        title: 'Config b title'
    }
};

// MaybeConfigKey value comes from some API so it's not always ConfigKey
function getConfigTitleOrFallback(maybeConfigKey: string) {

    // config[maybeConfigKey] throws this error.
    const configForKey = config[maybeConfigKey];

    if (configForKey) {
        return configForKey.title;
    }

    return 'Fallback value';
}

const title = config[ConfigKey.ConfigA].title;

console.log(title);

Выдает ошибку в заголовке. Я нашел способ решить эту проблему с помощью

a) Установка типа конфигурации на:

Record<string, ConfigValue>

Это не работает для меня, так как тогда он не проверяет, все ли ключи конфигурации существуют наверняка, и в других местах кода я использую config [ConfigKey.ConfigA]. Это должно быть безопасно и всегда возвращаться с заголовком.

б) Также можно использовать {suppressImplicitAnyIndexErrors: true}, но я не хочу этого делать, потому что это не кажется хорошей практикой.

Можно ли решить / подойти к этой проблеме другим, более эффективным способом?

Ответы [ 2 ]

1 голос
/ 25 мая 2020

Одним из способов было бы создать охрану типа :

const isConfigKey = (value: string): value is ConfigKey => {
  // For brevity
  return value === ConfigKey.ConfigA || value === ConfigKey.ConfigB;
}

А затем использовать его в своей getConfigTitleOrFallback функции:

function getConfigTitleOrFallback(maybeConfigKey: string) {
  if (!isConfigKey(maybeConfigKey)) {
    return 'Fallback value';
  }

  // Something like
  return config[maybeConfigKey].title;
}

Другой способ было бы использовать ts-type-checked, преобразователь TypeScript, который может генерировать эти типы защиты для вас.

Отказ от ответственности: я являюсь автором библиотеки :)

0 голосов
/ 25 мая 2020

Если вы ожидаете, что ключ не всегда будет иметь тип ConfigKey, вам нужно будет указать машинописному тексту, что он также может быть строкой

Например,

  type ConfigValue = {
    title: string;
}

const enum ConfigKey {
    ConfigA = 'config-a',
    ConfigB = 'config-b'
}

// For each ConfigKey there must exist a record so I can't type it as Record<string, ConfigValue>. Doing config[ConfigKey.ConfigA] should be a safe action.
const config: Record<ConfigKey | string, ConfigValue> = {
    [ConfigKey.ConfigA]: {
        title: 'Config a title'
    },
    [ConfigKey.ConfigB]: {
        title: 'Config b title'
    }
};

// MaybeConfigKey value comes from some API so it's not always ConfigKey
function getConfigTitleOrFallback(maybeConfigKey: ConfigKey | string) {

    // config[maybeConfigKey] throws this error.
    const configForKey = config[maybeConfigKey];

    if (configForKey) {
        return configForKey.title;
    }

    return 'Fallback value';
}

const title = config[ConfigKey.ConfigA].title;

console.log(title);

Если вы не Неважно, что вы также можете просто привести ключ к ConfigKey, так как вы уже возвращаете резервное значение в случае несуществующего ключа, вы должны быть в безопасности:

function getConfigTitleOrFallback(maybeConfigKey: string) {

        // config[maybeConfigKey] throws this error.
        const configForKey = config[maybeConfigKey as ConfigKey];

        if (configForKey) {
            return configForKey.title;
        }

        return 'Fallback value';
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...