Как мне преобразовать строку в enum в TypeScript?

Я определил следующее перечисление в TypeScript:

enum Color{
    Red, Green
}

Теперь в моей функции я получаю цвет в виде строки. Я пробовал следующий код:

var green= "Green";
var color : Color = <Color>green; // Error: can't convert string to enum

Как я могу преобразовать это значение в перечисление?

Ответ 1

Перечисления в TypeScript 0.9 основаны на строках и цифрах. Вам не нужно вводить утверждение типа для простых преобразований:

enum Color{
    Red, Green
}

// To String
 var green: string = Color[Color.Green];

// To Enum / number
var color : Color = Color[green];

Попробуйте в Интернете

У меня есть документация об этом и других шаблонах Enum в моей книге OSS: https://basarat.gitbooks.io/typescript/content/docs/enums.html

Ответ 2

Как из Typescript 2.1 строковые ключи в перечислениях строго типизированы. keyof typeof используется для получения информации о доступных строковых клавишах (1):

enum Color{
    Red, Green
}

let typedColor: Color = Color.Green;
let typedColorString: keyof typeof Color = "Green";

// Error "Black is not assignable ..." (indexing using Color["Black"] will return undefined runtime)
typedColorString = "Black";

// Error "Type 'string' is not assignable ..." (indexing works runtime)
let letColorString = "Red";
typedColorString = letColorString;

// Works fine
typedColorString = "Red";

// Works fine
const constColorString = "Red";
typedColorString = constColorString

// Works fine (thanks @SergeyT)
let letColorString = "Red";
typedColorString = letColorString as keyof typeof Color;

typedColor = Color[typedColorString];

https://www.typescriptlang.org/docs/handbook/advanced-types.html#index-types

Ответ 3

Эта заметка относится к basarat answer, а не к исходному вопросу.

У меня была странная проблема в моем собственном проекте, где компилятор сообщал ошибку, примерно эквивалентную "невозможно преобразовать строку в цвет", используя эквивалент этого кода:

var colorId = myOtherObject.colorId; // value "Green";
var color: Color = <Color>Color[colorId]; // TSC error here: Cannot convert string to Color.

Я обнаружил, что вывод метода компилятора сбился с толку, и он думал, что colorId является значением перечисления, а не идентификатором. Чтобы устранить проблему, я должен был указать идентификатор в виде строки:

var colorId = <string>myOtherObject.colorId; // Force string value here
var color: Color = Color[colorId]; // Fixes lookup here.

Я не уверен, что вызвало проблему, но я оставлю это примечание здесь, если кто-то столкнется с той же проблемой, что и я.

Ответ 4

Если вы уверены, что входная строка точно совпадает с Color enum, используйте:

const color: Color = (<any>Color)["Red"];

В случае, если входная строка может не соответствовать Enum, используйте:

const mayBeColor: Color | undefined = (<any>Color)["WrongInput"];
if (mayBeColor !== undefined){
     // TypeScript will understand that mayBeColor is of type Color here
}

площадка


Если мы не приведем тип enum к типу <any>, тогда TypeScript покажет ошибку:

Элемент неявно имеет тип 'any', потому что индексное выражение не относится к типу 'number'.

Это означает, что по умолчанию тип TypeScript Enum работает с числовыми индексами, т.е. let c = Color[0], но не со строковыми индексами, такими как let c = Color["string"]. Это известное ограничение команды Microsoft для более общей проблемы Индексы строк объекта.

Ответ 5

Я получил его с помощью следующего кода.

var green= "Green";
var color : Color= <Color>Color[green];

Ответ 6

Я также столкнулся с той же ошибкой компилятора. Просто небольшая вариация подхода Sly_ Cardinal.

var color: Color = Color[<string>colorId];

Ответ 7

Если компилятор TypeScript знает, что тип переменной - строка, это работает:

let colorName : string = "Green";
let color : Color = Color[colorName];

В противном случае вы должны явно преобразовать его в строку (чтобы избежать предупреждений компилятора):

let colorName : any = "Green";
let color : Color = Color["" + colorName];

Во время выполнения оба решения будут работать.

Ответ 9

В этом вопросе много смешанной информации, поэтому давайте рассмотрим всю реализацию для TypeScript 2. x+ в Руководстве Ника по Использованию Enums в моделях с TypeScript.

Это руководство предназначено для: тех, кто создает код на стороне клиента, который принимает от сервера набор известных строк, который будет удобно моделироваться как Enum на стороне клиента.

Определить перечисление

Давайте начнем с перечисления. Это должно выглядеть примерно так:

export enum IssueType {
  REPS = 'REPS',
  FETCH = 'FETCH',
  ACTION = 'ACTION',
  UNKNOWN = 'UNKNOWN',
}

Здесь следует отметить две вещи:

  1. Мы явно объявляем их как регистры перечисления со строковыми данными, что позволяет нам создавать их экземпляры со строками, а не с некоторыми другими не связанными числами.

  2. Мы добавили параметр, который может существовать или не существовать в нашей модели сервера: UNKNOWN. Это может быть обработано как undefined если вы предпочитаете, но я хотел бы избежать | undefined | undefined типы по возможности, чтобы упростить обработку.

UNKNOWN случая UNKNOWN является то, что вы можете быть действительно очевидны в коде и делать стили для неизвестных перечисляемых случаев ярко-красными и мигающими, чтобы вы знали, что вы что-то неправильно обрабатываете.

Разобрать перечисление

Возможно, вы используете это перечисление, встроенное в другую модель, или все в одиночку, но вам придется проанализировать перечисление со строковым типом y из JSON или XML (ха) в свой строго типизированный аналог. Встраиваемый в другую модель, этот синтаксический анализатор живет в конструкторе класса.

parseIssueType(typeString: string): IssueType {
  const type = IssueType[typeString];
  if (type === undefined) {
    return IssueType.UNKNOWN;
  }

  return type;
}

Если перечисление правильно проанализировано, оно в конечном итоге будет иметь правильный тип. В противном случае оно будет undefined и вы можете перехватить его и вернуть свой UNKNOWN случай. Если вы предпочитаете использовать undefined качестве неизвестного случая, вы можете просто вернуть любой результат из попытки анализа enum.

Оттуда, это только вопрос использования функции анализа и использования вашей новой строго типизированной переменной.

const strongIssueType: IssueType = parseIssueType('ACTION');
// IssueType.ACTION
const wrongIssueType: IssueType = parseIssueType('UNEXPECTED');
// IssueType.UNKNOWN

Ответ 10

Мне нужно было знать, как перебирать значения перечислений (тестировал множество перестановок нескольких перечислений), и я обнаружил, что это хорошо работает:

export enum Environment {
    Prod = "http://asdf.com",
    Stage = "http://asdf1234.com",
    Test = "http://asdfasdf.example.com"
}

Object.keys(Environment).forEach((environmentKeyValue) => {
    const env = Environment[environmentKeyValue as keyof typeof Environment]
    // env is now equivalent to Environment.Prod, Environment.Stage, or Environment.Test
}

Ответ 11

Я искал ответ, который мог бы получить enum из string, но в моем случае значения перечислений имели разные строковые значения. У ОП было простое перечисление для Color, но у меня было что-то другое:

enum Gender {
  Male = 'Male',
  Female = 'Female',
  Other = 'Other',
  CantTell = "Can't tell"
}

Когда вы пытаетесь разрешить Gender.CantTell с помощью строки "Can't tell", он возвращает undefined с исходным ответом.

Еще один ответ

По сути, я придумал другой ответ, вдохновленный этим ответом:

export const stringToEnumValue = <ET, T>(enumObj: ET, str: string): T =>
  (enumObj as any)[Object.keys(enumObj).filter(k => (enumObj as any)[k] === str)[0]];

Notes

  • Мы берем первый результат filter, предполагая, что клиент передает допустимую строку из перечисления. Если это не так, будет возвращено undefined.
  • Мы приводим enumObj к any, потому что с TypeScript 3. 0+ (в настоящее время используется TypeScript 3.5), enumObj разрешается как unknown.

Пример использования

const cantTellStr = "Can't tell";

const cantTellEnumValue = stringToEnumValue<typeof Gender, Gender>(Gender, cantTellStr);
console.log(cantTellEnumValue); // Can't tell

Примечание: И, как кто-то указал в комментарии, я также хотел использовать noImplicitAny.

Ответ 12

Enum

enum MyEnum {
    First,
    Second,
    Three
}

Пример использования

const parsed = Parser.parseEnum('FiRsT', MyEnum);
// parsed = MyEnum.First 

const parsedInvalid= Parser.parseEnum('other', MyEnum);
// parsedInvalid = undefined

Игнорировать регистрозависимый анализ

class Parser {
    public static parseEnum<T>(value: string, enumType: T): T[keyof T] | undefined {
        if (!value) {
            return undefined;
        }

        for (const property in enumType) {
            const enumMember = enumType[property];
            if (typeof enumMember === 'string') {
                if (enumMember.toUpperCase() === value.toUpperCase()) {
                    const key = enumMember as string as keyof typeof enumType;
                    return enumType[key];
                }
            }
        }
        return undefined;
    }
}

Ответ 13

Попробуйте это

var color: Color = (Color as any)["Green];

Это прекрасно работает для версии 3.5.3

Ответ 14

Перечисления, созданные так, как вы это сделали, скомпилированы в объект, в котором хранятся как прямые (name → value) и обратные (value → name) отображения. Как мы можем наблюдать из этого скриншота Chrome Devtools:

enter image description here

Вот пример того, как работает двойное сопоставление и как приводить от одного к другому:

enum Color{
    Red, Green
}
// To Number
var greenNr: number = Color['Green'];
console.log(greenNr); // logs 1

// To String
var greenString: string = Color[Color['Green']];  // or Color[Color[1]
console.log(greenString); // logs Green

// In your example

// recieve as Color.green instead of the string green
var green: string = Color[Color.Green];  

// obtain the enum number value which corresponds to the Color.green property
var color: Color = (<any>Color)[green];  

console.log(color); // logs 1