Enum исчерпывающей проверки не удается, когда Enum является универсальным - PullRequest
1 голос
/ 26 февраля 2020

В TypeScript вы можете проверить Enums исчерпывающе (например, в операторах switch).

Проблема

Мне нужно использовать Enum как Generi c, потому что я хочу ограничить другие параметры в соответствии с до предоставленного enumVal.

Я знаю, что для этого простого примера проще всего соответствующим образом перегрузить функцию, но это становится непрактичным, когда есть много возможных комбинаций. Например, для следующего перечисления:

Пример

enum MyEnum {
  FOO = 'foo',
  BAR = 'bar'
}

это работает:

function exhaustiveSwitch(enumVal: MyEnum) {
  switch (enumVal) {
    case MyEnum.FOO:
      break
    case MyEnum.BAR:
      break
    default:
      const _exhaustiveCheck: never = enumVal
  }
}

Но когда я использую Enum в качестве Generi c, он говорит Type 'EnumVal' is not assignable to type 'never':

function exhaustiveSwitchGeneric<EnumVal extends MyEnum> (enumVal: EnumVal) {
  switch (enumVal) {
    case MyEnum.FOO:
      break
    case MyEnum.BAR:
      break
    default:
      const _exhaustiveCheck: never = enumVal //Type 'EnumVal' is not assignable to type 'never'
  }
}

(см. здесь )

Вопрос

  1. Почему это не работает при использовании Enum в качестве Generi c?
  2. Есть ли другой способ использовать точное предоставленное значение (например, MyEnum.FOO) для другого параметра без универсальных параметров? (исключая перегрузку функций)

Вполне может быть веская причина, но, насколько я понимаю, использование Generi c должно привести к тому же результату, что и его непосредственное использование.

1 Ответ

0 голосов
/ 26 февраля 2020

Проблема еще больше. Нет возможности расширять Enums в TypeScript, для этого нет синтаксиса, и он не поддерживается, поэтому ваш код EnumVal extends MyEnum будет работать только для MyEnum. Если вы хотите расширить какой-либо вариант, создать буквальное объединение, например 'foo' | 'bar', тогда расширение имеет смысл.

Ниже приведено доказательство невозможности расширения Enum:

enum MyEnum {
  FOO = 'foo',
  BAR = 'bar'
}

enum MySubEnum {
  FOO = 'foo',
}

type MySubEnumExtendsMyEnum = MySubEnum extends MyEnum ? true : false // false
exhaustiveSwitchGeneric(MySubEnum.FOO)
// compile error: 
// Argument of type 'MySubEnum' is not assignable to parameter of type 'MyEnum'.

И последнее Плохая новость - эксклюзивный переход с дженериков невозможен. Но, к счастью, мы можем сделать некоторые обходные пути. Ниже приведен пример использования строковых литералов, как я уже сказал, нет возможности расширять Enum. Рассмотрим:

type MyVariant = 'foo' | 'bar';
type SubVariant = 'foo';

type SubVariantExtendsMyVariant = SubVariant extends MyVariant ? true : false; // true

function exhaustiveSwitchGeneric<Val extends MyVariant>(val: Val) {
  const v = val as MyVariant // important line
  switch (v) {
    case 'foo':
      break
    case 'bar':
      break
    default:
      const _a: never = v;
  }
}

У нас есть трюк, работающий на val as MyVariant, коммутатор эксклюзивный и должен иметь все варианты MyVariant

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