TypeScript course menu
TypeScript Union Types: Values That Can Be One of Several Types
Learn TypeScript union types with the | operator: unions of primitives, unions with null and undefined, what you can do with a union before narrowing, unions of object types, arrays of unions, and how unions model real data.
On this page
A union type describes a value that can be one of several types. It is written with a vertical bar: string | number means "a string or a number". Unions are everywhere in real TypeScript code, because real data often comes in more than one form.
A first union#
function formatId(id: string | number): string {
return `ID-${id}`;
}
console.log(formatId(42));
console.log(formatId("A7"));ID-42
ID-A7Any value that matches one of the members is accepted. Anything else is rejected:
function formatId(id: string | number): string {
return `ID-${id}`;
}
formatId(true);error TS2345: Argument of type 'boolean' is not assignable to parameter of type 'string | number'.You can only use what all members share#
With a union, TypeScript only allows operations that are valid for every member:
function shout(value: string | number) {
return value.toUpperCase();
}error TS2339: Property 'toUpperCase' does not exist on type 'string | number'.toUpperCase exists on strings but not numbers. Methods both types have, such as toString(), are allowed. To use type-specific features, first narrow the union with a check:
function shout(value: string | number): string {
if (typeof value === "string") {
return value.toUpperCase(); // value is string here
}
return value.toFixed(1); // value is number here
}
console.log(shout("hello"), shout(3));HELLO 3.0Narrowing is so central to unions that it has its own lesson: Narrowing.
Unions with null and undefined#
A very common union marks a value as possibly missing:
function findUser(id: number): { name: string } | undefined {
const users = [{ id: 1, name: "Asha" }];
return users.find((u) => u.id === id);
}
const user = findUser(2);
console.log(user?.name ?? "No such user");No such userThe return type tells every caller that the user might not be found, and strict mode makes them handle it. See null, undefined and Strict Null Checks.
Unions of literal values#
Unions of specific values are an excellent way to restrict a string to a known set:
type Size = "small" | "medium" | "large";
function price(size: Size): number {
return size === "small" ? 120 : size === "medium" ? 160 : 200;
}
console.log(price("medium"));160type Size = "small" | "medium" | "large";
const s: Size = "extra-large";error TS2322: Type '"extra-large"' is not assignable to type 'Size'.Editors also auto-complete the allowed values. More in Literal Types.
Unions of object types#
type Card = { method: "card"; last4: string };
type Upi = { method: "upi"; upiId: string };
type Payment = Card | Upi;
function describe(p: Payment): string {
if (p.method === "card") return `Card ending ${p.last4}`;
return `UPI ${p.upiId}`;
}
console.log(describe({ method: "card", last4: "4242" }));
console.log(describe({ method: "upi", upiId: "asha@okbank" }));Card ending 4242
UPI asha@okbankThe shared method property, with a different literal value in each member, lets TypeScript tell the members apart. This pattern, a discriminated union, is one of the most useful in TypeScript; see Discriminated Unions.
Arrays and unions#
Watch the parentheses:
Practice#
Practice exercise
Write toArray(value: string | string[]): string[] that always returns an array, and lengthOf(value: string | unknown[] | null): number that returns the length, or 0 for null. Test both.
Show solution
function toArray(value: string | string[]): string[] {
return typeof value === "string" ? [value] : value;
}
function lengthOf(value: string | unknown[] | null): number {
if (value === null) return 0;
return value.length; // both strings and arrays have length
}
console.log(toArray("a"), toArray(["b", "c"]));
console.log(lengthOf("hello"), lengthOf([1, 2]), lengthOf(null));[ 'a' ] [ 'b', 'c' ]
5 2 0After ruling out null, value.length is allowed because every remaining member has a length.
Key takeaway#
Finished this lesson?