Как преобразовать строку в перечисление в TypeScript?

165

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

enum Color{
    Red, Green
}

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

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

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

Теги:

8 ответов

237
Лучший ответ

Перечисления в 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

  • 54
    Это не работает с --noImplicitAny (в VS не --noImplicitAny «Разрешить неявные« любые »типы»). error TS7017: Index signature of object type implicitly has an 'any' type. Для меня это сработало: var color: Color = (<any>Color)[green]; (протестировано с версией 1.4)
  • 2
    @ Войта сказал правильно. Это не работает в VS 2012. Этот работал, но var color: Color = (<любой> цвет) [зеленый];
Показать ещё 5 комментариев
58

Как из 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
    Таким образом, мы можем использовать typecast: let s = "Green"; let typedColor = <keyof typeof Color> s;
  • 0
    Да, и замена let на const будет работать без приведения. Обновленный пример, чтобы прояснить это. Спасибо @SergeyT
24

Эта заметка относится к 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.

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

  • 0
    Спасибо! Это сводило меня с ума
16

Получил работу с использованием следующего кода.

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

Если вы уверены, что строка ввода имеет точное совпадение с перечислением цвета, используйте:

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

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

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

Игровая площадка


Если мы не используем тип enum to <any>, тогда tsc покажет ошибку

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

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

  • 0
    Вы также можете привести к <keyof typeof Color>. Также «0» также является неправильным вводом, но не возвращает неопределенное значение, поэтому проверьте typeof mayBeColor === 'number'
8

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

var color: Color = Color[<string>colorId];
  • 0
    В качестве дополнения: если у вас есть перечисление машинописного текста, заполненное слоем javascript, который сериализует перечисление как строку (например, Asp Web API через AngularJS), вы можете сделать myProp.color = Color[<string><any>myProp.color] Ура
  • 0
    Это должен быть признанный ответ.
7

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

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

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

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

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

  • 2
    почему бы просто не использовать typecast <string>colorName вместо "" + colorName ?
0

В этом вопросе много смешанной информации, поэтому давайте рассмотрим всю реализацию 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
  • 1
    К сожалению, это кажется неправильным или, по крайней мере, не обобщаемым. Это работает, потому что ваши ключи равны строкам, которые им присвоены. Если они, как в моем случае, отличаются, однако, это не работает. В словах документации : «Имейте в виду, что члены строкового перечисления вообще не генерируют обратное отображение». Ваш код будет скомпилирован в нечто вроде IssueType["REPS"]="REPS" . Если бы вы определили свое перечисление немного по-другому, скажем, REPS="reps" это привело бы к IssueType["REPS"]="reps" что бы ...
  • 0
    ... всегда возвращайте IssueType.UNKNOWN потому что в вашем перечислении нет ключевых reps . Жаль, что я до сих пор не нашел рабочего решения для этого, так как мои строки содержат дефисы, которые делают их непригодными в качестве ключей.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню