Машинопись `enum` из строки JSON

Есть ли способ сделать перечисление TypeScript совместимым со строками из JSON?

Например:

enum Type { NEW, OLD }

interface Thing { type: Type }

let thing:Thing = JSON.parse('{"type": "NEW"}');

alert(thing.type == Type.NEW); // false

я мог былайк thing.type == Type.NEW быть правдой. Или, более конкретно, я хотел бы указатьenum значения должны быть определены какстроки, а не цифры.

Я знаю, что я могу использоватьthing.type.toString() == Type[Type.NEW] но это громоздко и, кажется, делает аннотацию типа enum запутанной и вводящей в заблуждение, что противоречит ее цели. JSON техническине указав допустимое значение перечисления, поэтому я не должен вводить это свойство в перечисление.

Поэтому вместо этого я использую строковый тип со статическими константами:

const Type = { NEW: "NEW", OLD: "OLD" }

interface Thing { type: string }

let thing:Thing = JSON.parse('{"type": "NEW"}');

alert(thing.type == Type.NEW); // true

Это дает мне использование, которое я хочу, но аннотацию типаstring слишком широк и подвержен ошибкам.

Я немного удивлен, что в расширенном наборе JavaScript нет строковых перечислений. Я что-то пропустил? Есть ли другой способ сделать это?

Обновление TS 1.8

С помощьюстроковые литеральные типы другая альтернатива (спасибо @basaret), но чтобы получить желаемое использование типа enum (см. выше), необходимо определить ваши значениядважды: один раз в строковом литеральном типе и один раз в качестве значения (константа или пространство имен):

type Type = "NEW" | "OLD";
const Type = {
    NEW: "NEW" as Type,
    OLD: "OLD" as Type
}

interface Thing { type: Type }

let thing:Thing = JSON.parse(`{"type": "NEW"}`);

alert(thing.type === Type.NEW); // true

Это работает, но требует много шаблонов, достаточно, чтобы я не использовал его большую часть времени. Сейчас я надеюсь, чтопредложение дляstring enums в конечном итоге сделает дорожную карту.

Обновление TS 2.1

Новыйkeyof поиск типа позволяет генерировать строковый литерал из ключей const или пространства имен, что делает определениенемного менее избыточный:

namespace Type {
    export const OLD = "OLD";
    export const NEW = "NEW";
}
type Type = keyof typeof Type;

interface Thing { type: Type }

const thing: Thing = JSON.parse('{"type": "NEW"}');
thing.type == Type.NEW // true

Обновление TS 2.4

В TypeScript 2.4 добавлена ​​поддержка строковых перечислений! Приведенный выше пример становится:

enum Type {
    OLD = "OLD",
    NEW = "NEW"
}

interface Thing { type: Type }
const thing: Thing = JSON.parse('{"type": "NEW"}');
alert(thing.type == Type.NEW) // true

Это выглядитоколо идеально, но все еще есть душевная боль:

Выеще нужно записать значение дважды, т.е.OLD = "OLD"и нет подтверждения, что у вас нет опечатки, какNEW = "MEW"... это уже укусила меня в реальном коде.

Есть некоторые странности (возможно, ошибки?) С тем, как перечисление проверяется типом enum, это не просто сокращение типа строкового литерала, что было бы действительно правильно. Некоторые проблемы, с которыми я столкнулся:

enum Color { RED = "RED", BLUE = "BLUE", GREEN = "GREEN" }

type ColorMap = { [P in Color]: number; }

declare const color: Color;
declare const map: ColorMap;
map[color] // Error: Element implicitly has an 'any' type because type 'ColorMap' has no index signature.

const red: Color = "RED"; // Type '"RED"' is not assignable to type 'Color'.
const blue: Color = "BLUE" as "RED" | "BLUE" | "GREEN"; // Error: Type '"RED" | "BLUE" | "GREEN"' is not assignable to type 'Color'.

Эквивалентный код сenum Color заменены строковые литералы, работают нормально ...

Да, я думаю, что у меня есть ОКР по этому поводу, я просто хочу, чтобы мои идеальные JS перечисления. :)

Ответы на вопрос(4)

Ваш ответ на вопрос