Union Types: When a Value Can Be One of Several Things
A Union Type is an 'OR' for your types, letting a value be one of several options, like `string | number`. Use it for flexible function arguments or varied API responses. The footgun: you can only use properties common to all types until you narrow.
WHY IT EXISTS: Sometimes a variable or parameter needs to accept a value from a small, fixed set of types. Using any sacrifices all type safety, allowing bugs to pass silently at compile time. Creating complex class hierarchies is often overkill for simple cases like accepting either a string or a number. Union types solve this by providing a precise way to declare that a value can be one of a few specific types, and no others.
THE MENTAL MODEL: Think of a union type as an 'OR' gate for types. A variable of type A | B can hold a value of type A or a value of type B. It models situations where a value can legitimately be one of several things, composing a new type from a set of possibilities rather than from a set of properties.
HOW IT WORKS: You define a union type using the vertical bar | between two or more types, like type ID = string | number;. When you have a value of this union type, TypeScript only allows you to perform operations that are valid for every member type. For example, with a string | number type, you can't use a string method like .toUpperCase() directly because it doesn't exist on number. To access type-specific members, you must first 'narrow' the type. This involves using a runtime check, like typeof value === 'string', inside a conditional block to prove to the compiler which specific type the value currently holds.
WHEN TO USE IT: Use union types when a function parameter can logically accept different kinds of input, like an ID that could be a string or a number. They are also excellent for modeling API responses that might return a success object or an error object, for example type ApiResponse = SuccessData | ErrorData;. This forces you to handle both cases explicitly in your code.
WHEN NOT TO USE IT: Avoid union types when you actually need a single, consistent object structure. If two object types in a union share many properties, it might be better to create a base interface and extend it. Also, avoid creating unions with too many members (string | number | boolean | MyObject | ...), as this can become as unmanageable as any and may signal a poor data model.
ONE CANONICAL EXAMPLE: A function that pads a string is a classic case. The padding can be specified as a number of spaces or as a literal string to prepend. function padLeft(value: string, padding: string | number) { if (typeof padding === "number") { return Array(padding + 1).join(" ") + value; } if (typeof padding === "string") { return padding + value; } throw new Error("Expected string or number."); } Here, the padding parameter is safely typed. The typeof checks narrow the union, allowing TypeScript to understand which logic is safe to execute within each block.
Read the original → typescriptlang.org
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.