Функция Typescript для преобразования члена перечисления строки в перечисление

Я хотел бы написать что-то вроде этого в Typescript:

export function stringToEnum<T>(enumObj: T, str: string): keyof T {
    return enumObj[str];
}

и используйте его следующим образом:

enum MyEnum {
  Foo
}

stringToEnum<MyEnum>(MyEnum, 'Foo');

куда бы он вернулся

MyEnum.Foo

Вышеприведенная функция работает, как и ожидалось... но при наборе ошибок возникают ошибки. Для параметра MyEnum в stringToEnum<MyEnum>(MyEnum, 'Foo');Машинопись жалуется, что:

Аргумент типа 'typeof MyEnum' не может быть назначен параметру типа 'MyEnum'

что имеет смысл... к сожалению. Любые идеи о том, как я могу обойти это?

3 ответа

Решение

Вы можете сделать все это без необходимости писать функцию:

enum Color {
    red,
    green,
    blue
}

// Enum to string
const redString: string = Color[Color.red];
alert(redString);

// String to enum
const str = 'red';
const redEnum: Color = Color[str];
alert(redEnum);

Или вы можете повеселиться с ним...

enum MyEnum {
  Foo,
  Bar
}

function stringToEnum<ET, T>(enumObj: ET, str: keyof ET): T{
    return enumObj[<string>str];
}

const val = stringToEnum<typeof MyEnum, MyEnum>(MyEnum, 'Foo');

// Detects that `foo` is a typo
const val2 = stringToEnum<typeof MyEnum, MyEnum>(MyEnum, 'foo');

Ваша подпись немного перепутана. Тип возврата должен быть T[keyof T] если вы намерены для метода вернуть значение перечисления. Тип str параметр также должен быть keyof T чтобы вы не могли передавать недопустимые строки, но это ограничит вас передачей строковых литералов в (или типизированные переменные типа keyof T, но нет string):

function stringToEnum<T>(enumObj: T, str: keyof T): T[keyof T]

Тогда либо не указывайте param типа, и пусть компилятор правильно выводит тип:

// type: Foo
// value: 0  
const result = stringToEnum(MyEnum, 'Foo');

Или вам нужно предоставить typeof MyEnum в качестве параметра типа:

// type: Foo
// value: 0  
const result = stringToEnum<typeof MyEnum>(MyEnum, 'Foo');

Если вы действительно хотите иметь возможность передавать любое произвольное строковое имя перечисления, тогда возвращаемый тип - ложь: должно быть T[keyof T] | undefined, Вы также столкнетесь с проблемами при попытке enumObj[str] если тип str является string и у тебя есть noImplicitAny опция компилятора включена.

Есть еще кое-что для создания универсальных функций, которые правильно работают с типами перечислений, особенно числовых перечислений, которые имеют записи обратного просмотра во время выполнения. Посмотрите на исходный код ts-enum-util ( github, npm) для вдохновения

 stringToEnum(MyEnum, 'Foo');

Просто оставьте общий и пусть машинопись делает это. Это потому, что тип, хранящийся в MyEnum, не соответствует самому Enum, но является типом объединения его значений:

 enum Test { A, B };

 const value: Test /* "A" | "B" */ = Test.A;
Другие вопросы по тегам