Literal Types

Exact Values as Types

A literal type is a single exact value: "UPI", 42, true. Combining literals with | gives you a fixed list of allowed values, like a lightweight enum.

Example

type Size = "S" | "M" | "L" | "XL";
type Rating = 1 | 2 | 3 | 4 | 5;

function addToCart(product: string, size: Size): string {
  return `${product} (size ${size}) added`;
}

const stars: Rating = 4;
console.log(addToCart("Cotton T-Shirt", "M"));
console.log("Rated", stars, "stars");

Output

Cotton T-Shirt (size M) added
Rated 4 stars

A Value Outside the List

Example

"XXL" is not one of the allowed sizes (TS2345). Your editor also autocompletes the four valid options.

type Size = "S" | "M" | "L" | "XL";

function addToCart(product: string, size: Size): void {
  console.log(product, size);
}

addToCart("Hoodie", "XXL");

Compiler output (tsc)

Line 7: error TS2345: Argument of type '"XXL"' is not assignable to parameter of type 'Size'.

let vs const Inference

Example

const keeps the literal type; let widens it to string because it might change. That is why passing a let variable to a literal parameter can fail. Use as const or an annotation to keep it narrow.

type Method = "GET" | "POST";
function request(url: string, method: Method): string {
  return method + " " + url;
}

const m1 = "GET";               // type "GET"
let m2: Method = "POST";        // annotated
const opts = { method: "GET" } as const; // method is "GET", not string

console.log(request("/products", m1));
console.log(request("/orders", m2));
console.log(request("/cart", opts.method));

Output

GET /products
POST /orders
GET /cart