Union & Literal Types

The Course
•
5 min read

A union describes alternatives. string | number means a value may be a string or a number. It does not mean both at once, and it does not perform conversion. Before using an operation that works on only one alternative, your code must establish which one it has.

A literal type names an exact value, such as “planned”. A union of literals creates a small vocabulary: type Status = "planned" | "done". This catches misspellings at checked boundaries and makes supported states visible to readers.

Use literal unions for categories with distinct meanings. A boolean is fine for a true/false fact, but a status with planned, active and done has three meaningful possibilities. Do not encode it using unexplained numeric values.

A parameter annotated with Status accepts either allowed literal. When creating object records, annotate the intended record type if a property’s inferred type widens to string. The checker needs evidence that a changing string still belongs to the allowed set; it cannot assume that because you know it informally.

A type with many alternatives is not automatically a better model. Include only the states the application needs. At runtime a union has disappeared, so unknown text from outside the program still requires validation. Day 6 will make that boundary explicit.

Predict, check, then run

Before running, write down the output and explain which information the checker knows. Click Check types first, then Check & run.

Predict, then runTypeScript
type Status = "planned" | "done";

function badge(status: Status): string {
  return status === "done" ? "Complete" : "Next";
}

console.log(badge("planned"));
console.log(badge("done"));

Enable JavaScript to edit and type-check this example.

Check your prediction
Next
Complete

Read a real compiler error

The value is a string, but is it one of the allowed strings?

Find and fix the type errorTypeScript
type Status = "planned" | "done";

const status: Status = "finished";

console.log(status);

Enable JavaScript to edit and type-check this example.

Check your diagnosis

The literal “finished” is outside Status. Use “done” if it means the same thing. Add another alternative only when it represents a real state with defined behavior.

A const record can still have changing fields

A const binding prevents rebinding the variable; it does not freeze the record. In const task = { status: "planned" }, the status property usually widens to string because it can be changed. A string could contain an unsupported state, so it cannot automatically be passed to a Status parameter. Annotate the record’s intended shape when its fields have a restricted vocabulary.

Annotate a record statusTypeScript
type Status = "planned" | "done";

type Task = {
  topic: string;

  status: Status;
};

function badge(status: Status): string {
  return status === "done" ? "Complete" : "Next";
}

const task: Task = { topic: "Types", status: "planned" };

console.log(badge(task.status));
task.status = "done";
console.log(badge(task.status));

Enable JavaScript to edit and type-check this example.

Check your prediction
Next
Complete

Model a finite set of meaningful alternatives

A union describes alternatives; it does not convert one into another. A parameter accepting string|number must handle either kind. A literal union can instead restrict a value to a closed vocabulary such as planned or done.

Use a closed set when spelling is part of the domain contract. A broad string accepts accidental misspellings that a literal union rejects. The compiler still cannot prove which state should apply at runtime; your transition code chooses it.

Model a finite set of meaningful alternatives: traceTypeScript
type Status = "planned" | "done";

function next(status: Status): Status {
  return status === "planned" ? "done" : "planned";
}

console.log(next("planned"));
console.log(next("done"));

Enable JavaScript to edit and type-check this example.

Check your prediction
done
planned

Both return branches belong to the declared vocabulary. The function implements a toggle; if the intended rule were one-way completion, this type alone would not catch the behavioral mismatch.

Model a finite set of meaningful alternatives: contrastTypeScript
function label(value: string | number): string {
  return typeof value === "number" ? `${value} min` : value.trim();
}

console.log(label(0));
console.log(label(" Review "));

Enable JavaScript to edit and type-check this example.

Check your prediction
0 min
Review

The typeof branch supplies the evidence for the number-specific behavior. A union is not permission to call methods supported by only one of its members without checking first.

Try the rule on new inputs

Try a misspelled status and explain the rejected assignment. Then add a new legitimate status and identify every function whose behavior must change, even if its current type still compiles.

Your turn

Exercise

Union & Literal Types: practise

Define Priority as “low” | “high”. Write priorityLabel returning “Do soon” for high and “Later” for low. Check both outputs.

Your workspaceTypeScript
// Define the union and a typed function. Use if/else or a conditional expression.

Enable JavaScript to edit and type-check this example.

Hint 1: the idea

The parameter describes the vocabulary your function accepts.

Hint 2: a first step

Compare the priority with the exact literal “high”.

Show one solution
One possible solutionTypeScript
type Priority = "low" | "high";

function priorityLabel(priority: Priority): string {
  return priority === "high" ? "Do soon" : "Later";
}

console.log(priorityLabel("high"));
console.log(priorityLabel("low"));

Enable JavaScript to edit and type-check this example.

Do soon
Later

Explain the types at the function boundary and the runtime checks, if any. Compare your approach before copying this answer.

Change it and explain it

Try passing “urgent”. Should you expand the union or fix the caller? Answer based on the application’s vocabulary. Then add a third priority deliberately and update the function so it has a meaningful label.

Was this article helpful?

Your response is saved on this device.