简体   繁体   中英

How to use TS type as a value

I have a TypeScript type which has a bunch of strings and it's defined like this:

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

I then later on in my code get the region from the URL via query-string parameters. Let's say that the retrieved region from URL is a variable named region

So i'm doing some validation in my code and I want make sure the region is of the type Regions .

So in order to do the validation my code says: if (region in Regions) { doStuff();}

Which would work if Region was a variable with all those regions.

However since Regions is a type, it's throwing an error saying: 'Regions' only refers to a type, but is being used as a value here

Which I understand why, but how can I achieve what i want to do using or extending the type Regions

I really don't want to create another object or array of strings, I just want use my existing type to do this validation.

I did create an enum like this:

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

and then did region in RegionsList but this is kinda duplicating my Regions type already, and there has to be a better solution that combines the 2. Any help/suggestions is appreciated.

You can't make a value from a type, but you can infer a type from a value. That implies you should start with some runtime value and have the compiler infer the Regions type from it.


For example, you can make an array of valid region names:

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];

You can verify that the type Regions is the same as in your definition. Then you can use the array to check that a string is a valid Regions (such as when you implement a user-defined type guard function ):

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

Or, if you want to use in , you can make an object whose keys are the values you care about, instead of making an array:

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;

And again you can verify that Regions is the right type, and use in :

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

You could use an enum as above, but you'd need to be careful, since numeric enums have a reverse mapping and so "0" in RegionsEnum is true , possibly surprisingly. If you would still rather use that, it could look like this:

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;
}

(notice the extra bit of code making sure that region is not a "numeric string").


Okay, hope that helps; good luck!

Playground link to code

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM