A literal is a more concrete sub-type of a collective type.
What this means is that "Hello World"
is a string
, but a string
is not "Hello World"
inside the type system.
There are two sets of literal types available in TypeScript today, strings and numbers, by using literal types you can allow an exact value which a string or number must have.
Literal Narrowing
When you declare a variable via var
or let
, you are telling the compiler that there is the chance that this variable will change its contents.
In contrast, using const
to declare a variable will inform TypeScript that this object will never change.
ts// We're making a guarantee that this variable // helloWorld will never change, by using const. // So, TypeScript sets the type to be "Hello World" not string const helloWorld const helloWorld: "Hello World"= "Hello World"; // On the other hand, a let can change, and so the compiler declares it a string let hiWorld let hiWorld: string= "Hi World";
The process of going from an infinite number of potential cases (there are an infinite number of possible string values) to a smaller, finate number of potential case (in helloWorld
’s case: 1) is called narrowing.
String Literal Types
In practice string literal types combine nicely with union types, type guards, and type aliases. You can use these features together to get enum-like behavior with strings.
tstype Easing = "ease-in" | "ease-out" | "ease-in-out"; class UIElement { animate(dx: number, dy: number, easing: Easing) { if (easing === "ease-in") { // ... } else if (easing === "ease-out") { } else if (easing === "ease-in-out") { } else { // error! should not pass null or undefined. } } } let button = new UIElement(); button.animate(0, 0, "ease-in"); button.animate(0, 0, "uneasy"); // error: "uneasy" is not allowed here
You can pass any of the three allowed strings, but any other string will give the error
Argument of type '"uneasy"' is not assignable to parameter of type '"ease-in" | "ease-out" | "ease-in-out"'
String literal types can be used in the same way to distinguish overloads:
tsfunction createElement(tagName: "img"): HTMLImageElement; function createElement(tagName: "input"): HTMLInputElement; // ... more overloads ... function createElement(tagName: string): Element { // ... code goes here ... }
Numeric Literal Types
TypeScript also has numeric literal types.
tsfunction rollDice(): 1 | 2 | 3 | 4 | 5 | 6 { // ... }
These are seldom written explicitly, but they can be useful when narrowing issues and can catch bugs:
tsfunction foo(x: number) { if (x !== 1 || x !== 2) { // ~~~~~~~ // Operator '!==' cannot be applied to types '1' and '2'. } }
In other words, x
must be 1
when it gets compared to 2
, meaning that the above check is making an invalid comparison.