Как использовать тип TS в качестве значения - PullRequest
0 голосов
/ 26 мая 2020

У меня есть тип TypeScript, который имеет кучу строк, и он определяется следующим образом:

type Regions = "" | "eu-west-1" | "eu-east-1" | "us-west-1" | "us-east-1" | "ap-southeast-1" | "ap-east-1"

Затем я позже в своем коде получаю регион из URL-адреса через параметры строки запроса. Предположим, что полученная область из URL-адреса - это переменная с именем region

. Итак, я провожу некоторую проверку своего кода и хочу убедиться, что region имеет тип Regions.

Итак, чтобы выполнить проверку, мой код говорит: if (region in Regions) { doStuff();}

Что сработало бы, если бы Region был переменной со всеми этими регионами.

Однако, поскольку Regions - это тип, он выдает ошибку: 'Regions' only refers to a type, but is being used as a value here

Я понимаю, почему, но как я могу достичь того, что я хочу сделать, используя или расширяя type Regions

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

Я создал такое перечисление:

enum RegionsList {
  'eu-west-1',
  'eu-east-1',
  'us-west-1',
  'us-east-1',
  'ap-southeast-1',
  'ap-east-1'
}

, а затем сделал region in RegionsList, но это уже как бы дублирует мой тип регионов, и должно быть лучшее решение, объединяющее 2. Любая помощь / предложения приветствуются.

1 Ответ

3 голосов
/ 26 мая 2020

Вы не можете сделать значение из типа, но вы можете вывести тип из значения. Это означает, что вы должны начать с некоторого значения времени выполнения и заставить компилятор вывести из него тип Regions.


Например, вы можете создать массив допустимых имен регионов:

const Regions = ["", "eu-west-1", "eu-east-1", "us-west-1", 
  "us-east-1", "ap-southeast-1", "ap-east-1"] as const;
type Regions = typeof Regions[number];

Вы можете проверить, что тип Regions такой же, как в вашем определении. Затем вы можете использовать массив, чтобы проверить, что строка является допустимой Regions (например, когда вы реализуете функцию защиты определяемого пользователем типа ):

function checkRegion(region: string): region is Regions {
  return (Regions as readonly string[]).indexOf(region) >= 0;
}

Или, если вы хотите использовать in, вы можете создать объект, ключи которого являются значениями, которые вам нужны, вместо создания массива:

const Regions = {
  "": true,
  "eu-west-1": true,
  "eu-east-1": true,
  "us-west-1": true,
  "ap-southeast-1": true,
  "ap-east-1": true
}
type Regions = keyof typeof Regions;

И снова вы можете проверить, что Regions является правильный тип и используйте in:

function checkRegion(region: string): region is Regions {
  return region in Regions;
}

Вы можете использовать enum, как указано выше, но вам нужно быть осторожным, так как numeri * Перечисления 1045 * имеют обратное отображение , поэтому "0" in RegionsEnum равно true, что, возможно, удивительно. Если бы вы все же предпочли использовать это, это могло бы выглядеть так:

enum RegionsEnum {
  "", "eu-west-1", "eu-east-1", "us-west-1", "ap-southeast-1", "ap-east-1"
}
type Regions = keyof typeof RegionsEnum;
function checkRegion(region: string): region is Regions {
  return (region !== (+region) + "") && region in RegionsEnum;
}

(обратите внимание на дополнительный бит кода, удостоверяющий, что region не является "numeri c string").


Хорошо, надеюсь, это поможет; удачи!

Детская площадка ссылка на код

...