Specify Exact Values with TypeScript’s Literal Types

Marius Schulz
InstructorMarius Schulz

Share this video with your friends

Send Tweet
Published 5 years ago
Updated 3 years ago

A literal type is a type that represents exactly one value, e.g. one specific string or number. You can combine literal types with union types to model a finite set of valid values for a variable. In this lesson, we explore the all kinds of literal types in TypeScript:

  • String literal types
  • Numeric literal types
  • Boolean literal types
  • Enum literal types

Here's a simple variable declaration. It's valid JavaScript as there is no TypeScript specific syntax. The variable is inferred to be of type string because it's immediately initialized with a string value. If I change the let keyword to const however, the resulting type will be different.

TypeScript now infers a so-called string literal type. In our case, we get the string literal type on whose only valid value is the string on. I can also explicitly add a type annotation to the autocomplete variable. Notice that the syntax for string literal types looks exactly like the syntax for string literals.

You can also use single quotes if you want to, but I prefer to stick with double quotes. If I change the const keyword back to let, the variable still has the string literal type on because of our type annotation. We now get a type error if we try to assign any other string value.

String literal types are pretty useless in isolation, but they become really powerful if we combine them with union types. This way we can use the type system to model a finite set of valid values for the autocomplete variable, therefore assigning the string off is fine but assigning the string disabled is not.

The cool thing is that the TypeScript language service gives us smart autocompletion and suggests all valid string values. Also note that string literal types are case sensitive. If you wanted to accept the uppercase versions of the strings on and off as well, you would have to add additional string literal types to the union type.

Every string literal type is a subtype of string because, in the end, that's what our variable actually contains. This means we can call string methods on our variable and use it in places where string is expected. Let's move on to another kind of literal types called numeric literal types.

Here I'm creating a type alias called number base, and I'll assign to it the four number bases that I want to support here, which are 2, 8, 10, and 16 for binary, octal, decimal, and hexadecimal. Down below, I'll declare a variable called base of type number base.

The type checker is happy if I assign two to base, but it complains if I try to assign the value three to it because it's not a valid value in our union type. Another use case for numeric literal types would be an enumeration of all HTTP success status codes, such as the following.

To be fair, I don't find myself using numeric literal types that often, but they do have use cases in practice. For example, here's the type definition file for React. We're looking at the font weight property of an element here which can take a bunch of values. Like any other CSS property, it can be set to initial, inherit, or unset.

We also have four additional string values here that we can use, like normal, bold, bolder, and lighter. Finally, we can also assign a numeric weight between 100 and 900. Next up, Boolean literal types. Again, let's start with a simple variable declaration. We're setting autofocus to true and of course TypeScript infers the variable to be of type Boolean.

If I change the let keyword to const as we did before, we can now see that the autofocus variable has the Boolean literal type true. I can also explicitly add a type annotation here. If I change the const back to a let and try to assign the value false, we get a type error saying that type false is not assignable to type true.

To allow this assignment, I can create a union type and union together the Boolean literal types true and false. This union type is equivalent to the built-in type Boolean because, after all, Boolean only represents the two values true and false. Therefore I could also write Boolean here or I could leave out the type annotation entirely because autofocus will be inferred to be of type Boolean anyway.

Don't worry if all of this seems kind of pointless to you. We're going to look at a practical use case for a Boolean literal type in the next lesson. Let's finish up this lesson with the last remaining literal type, and that is an enum literal type.

We'll start out by creating an enum called protocols with three members HTTP, HTTPS, and FTP. Afterwards, we're going to create a type alias called hypertext protocol which represents the two cases HTTP and HTTPS of the protocols enum.

With these types in place, we can create a variable called protocol and add a type annotation of hypertext protocol. We can assign the cases HTTP and HTTPS to the variable, but we cannot assign FTP. If we attempt to do that, we get a type error saying that type protocols.FTP is not assignable to type hypertext protocol.

~ 4 years ago

Couldn't enums serve the same purpose?

Marius Schulz
Marius Schulzinstructor
~ 4 years ago

@Shobhit: Yes, enums and literal types serve similar purposes. Both specify a finite set of allowed value. However, enums are TypeScript-only construct; they don't exist in JavaScript. They're compiled to plain objects. Literal types only exist in the type system. They're completely compiled away and don't exist at runtime at all.

You can use literal types to specify exactly which string/number/boolean values are valid for a given property/parameter/…:

interface ScrollToOptions extends ScrollOptions {
    behavior?: "auto" | "instant" | "smooth";
    left?: number;
    top?: number;

declare function scrollTo(options?: ScrollToOptions): void;
~ 3 years ago

When you did the example of 2 | 4 | 6 etc... made me think "is there a way to type an 'even' number'.. so, instead of union typing 2|4|6|8|10 etc.... have some type that denotes "even"?

Marius Schulz
Marius Schulzinstructor
~ 3 years ago

@Dean: There's no even type or anything alike — literal types currently don't support that; you'll have to explicitly list all the values that you want to allow.