TypeScript Basics: Literal Types
Welcome to the Literal Types lesson!
This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!
We've seen basic types like
numberandstring. Every concrete number and every concrete string is also a type. For example, a variable of type1can only hold the number1. It can't hold2; that's a compile-time type error.>
let one: 1 = 1;one;Result:
1
>
let one: 1 = 2;one;Result:
type error: Type '2' is not assignable to type '1'.
>
let one: 1 = 'one';one;Result:
type error: Type '"one"' is not assignable to type '1'.
These are called literal types. For example, the type
1above is a literal number type. We can combine literal types with unions to allow only certain values.>
let oneOrTwo: 1 | 2 = 1;oneOrTwo;Result:
1
>
let oneOrTwo: 1 | 2 = 2;oneOrTwo;Result:
2
>
let oneOrTwo: 1 | 2 = 3;oneOrTwo;Result:
type error: Type '3' is not assignable to type '1 | 2'.
This seems like a strange feature at first, and most statically typed programming languages don't support it. However, it's very useful in practice and is used often in real-world TypeScript code.
For example, maybe we have a sort function. It can sort in either ascending ('asc') or descending ('desc') order.
>
function sort2(numbers: number[], direction: 'asc' | 'desc'): number[] {const sortable = numbers.slice(); // Clone the array.sortable.sort();if (direction === 'desc') {sortable.reverse();}return sortable;}- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
sort2([2, 1, 3], 'asc');Result:
[1, 2, 3]
- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
sort2([2, 1, 3], 'desc');Result:
[3, 2, 1]
- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
sort2([2, 1, 3], 'something else');Result:
type error: Argument of type '"something else"' is not assignable to parameter of type '"asc" | "desc"'.
We could theoretically have used a boolean above. But seeing
'asc'or'desc'is more descriptive thantrueorfalse.When we have more than two possible values, literal types really shine. For example, suppose that we're writing a database library.
>
type DatabaseType = 'mysql' | 'postgres' | 'oracle';let dbType: DatabaseType = 'mysql';dbType;Result:
'mysql'
>
type DatabaseType = 'mysql' | 'postgres' | 'oracle';let dbType: DatabaseType = 'msaccess';dbType;Result:
type error: Type '"msaccess"' is not assignable to type 'DatabaseType'.
With this type constraint in place, a user is immediately told if they try to use our library with an unsupported database. It will also tell them if they have a typo in the database name. They don't even have to run the application to see a failure. It can't run at all because it contains type errors.
trueandfalseare also literal types. A variable of typetruecan never befalse.>
let t: true = true;t;Result:
true
>
let t: true = false;t;Result:
type error: Type 'false' is not assignable to type 'true'.
Another way to think of a
booleantype is as atrue | false, which is a broader type than justtrue. This means that we can't assign a boolean to a variable of typetrue, since a boolean might sometimes befalse.By analogy: we can't assign a
number | stringto a variable of typenumber.>
function aBoolean(): boolean { return true; }let t: true = aBoolean();t;Result:
type error: Type 'boolean' is not assignable to type 'true'.