122

I know I can define string union types to restrict variables to one of the possible string values:

type MyType = 'first' | 'second' let myVar:MyType = 'first' 

I need to construct a type like that from constant strings, e.g:

const MY_CONSTANT = 'MY_CONSTANT' const SOMETHING_ELSE = 'SOMETHING_ELSE' type MyType = MY_CONSTANT | SOMETHING_ELSE 

But for some reason it doesn't work; it says MY_CONSTANT refers to a value, but it being used as a type here.

Why does Typescript allow the first example, but doesn't allow the second case? I'm on Typescript 3.4.5

5
  • 3
    Sounds like what you really want is an enum...? Commented May 22, 2019 at 18:53
  • 6
    You want type MyType = typeof MY_CONSTANT | typeof SOMETHING_ELSE. There's a big difference between types (which exist only at design time) and values (which exist at runtime) Commented May 22, 2019 at 18:53
  • I often throw this answer at people when I sense confusion between types and values. Commented May 22, 2019 at 18:56
  • @T.J.Crowder considered that, but I've got constant strings that are defined elsewhere that I want to use Commented May 22, 2019 at 20:17
  • @CanPoyrazoğlu - Fair enough, then Titian's answer is what you want. Commented May 23, 2019 at 6:45

4 Answers 4

172

To get the type of a variable you need to use the typeof type operator:

const MY_CONSTANT = 'MY_CONSTANT' // must be const, no annotation. let or var will not work const SOMETHING_ELSE = 'SOMETHING_ELSE' // must be const, no annotation. let or var will not work type MyType = typeof MY_CONSTANT | typeof SOMETHING_ELSE 

Playground

Note:

Since there seems to be a lot of confusion when people use this. The const matters. If you use other types of declarations (let or var) the final type would be string. Only const preserves string literal types.

Note 2:

For this solution to work you must not specify any type annotation on the const, and let the compiler infer the type of the constants (ex this will not work :const MY_CONSTANT: string = 'MY_CONSTANT')

Sign up to request clarification or add additional context in comments.

16 Comments

@CanPoyrazoğlu 'test' is both a value and a type (a string literal type), by definition (just like a class is a value, the constructor, and a type, the instance type)
typeof MY_CONSTANT will check if it is a whatever string, not specifically the MY_CONSTANT
If someone can explain the down-votes on this answer I would be grateful. I stand by the answer, it still does what it is supposed to and is an answer to the original question. If someone has issues with it let me know
@JonasRosenqvist please read the comments and the notes. Please check the playground link associated. If you use const then the literal type is preserved and type checking works as you expect and not all strings are compatible. If you have a sample where this is not true I would like to see it. Sorry if I sound a bit mad, but this answer keeps getting downvotes for no reason and it's getting very annoying. Not sure what I can do to make it more clear const is required
@TitianCernicova-Dragomir - you're right, I had made the mistake of declaring the constant as: const MY_CONSTANT:string = 'MY_CONSTANT' Specifying the type of constant made it accept any string. Sorry, you'll get my upvote!
|
22

You can also use enum for this case. For example:

// Define enum. enum myConstants { MY_CONSTANT = 'my_constant', SMTH_ELSE = 'smth_else' } // Use it in an interface for typechecking. interface MyInterface { myProp: myConstants } // Example of correct object - no errors. let a: MyInterface = { myProp: myConstants.MY_CONSTANT } // Incorrect value - TS reports an error. let b: MyInterface = { myProp: 'John Doe' } 

More about enums

1 Comment

This is exactly what I was looking for.
14

Enums cover the case quiet well:

export enum ITEM_TYPES { TYPE1 = 'text', TYPE2 = 'image' } export type IItemType = ITEM_TYPES.TYPE1 | ITEM_TYPES.TYPE2 

And then in code ITEM_TYPES can be refered to for all kind of runtime comparisons:

if (type === ITEM_TYPES.TYPE1){ } 

Comments

0

I made a post related to string literal union type. https://medium.com/@m.fatihalaziz/string-literal-union-type-with-typeguard-in-typescript-dff4c9741b4a

what it cover:

  • how to create a string literal union type
  • how to pass string as the string literal
  • how to use the type guard of typescript effectively

I hope it helps, Good Luck!

2 Comments

Thank you Fatih. Just read your article, it's very detailed and informative!
I'm so glad my post can help you, thanks!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.