TypeScript's unions are a powerful feature. Let's dive into what they are and how you can use them to your advantage! What is union type? A union type is a set of mutually exclusive types. The name (or ) comes from type theory. According to Wikipedia definition: union sum type The is a “tagged union”. That is, for types “A” and “B”, the type “A + B” holds either a term of type “A” or a term of type “B” and it knows which one it holds. sum type And in TypeScript, it's similar to type theory ( ). Let's look at how official documentation defines union type: as programming has a lot in common with the set, type, and category theory A union type is a type formed from two or more other types, representing values that may be of those types. We refer to each of these types as the union’s . any one members The most basic union type consists of two primitive types: type Union = number | string; // defined as inline type function getUserById(id: number | string) { // ... } This allows handling value which can be a . This is great to prove code is type-safe for all possible cases! either number string In this guide, I'm not going to discuss and and how by default they are assignable to anything. Please do yourself a favor and start using or at least strict null checks. null undefined strict When to use the union type? Union types are perfect to express a finite number of known options, either primitive literals or objects (as a discriminated unions which we'll discuss later), where single logic has to handle all the possible cases. A few great examples where union types shine are: (like React's ) finite state machines useReducer event names object fields (using keyword) keyof You shouldn't use union types where the amount of possible options is too large, for example, a person's name as there is an infinite number of options. Also, keep in mind, they exist only at the type level. They are stripped out during compilation. How to narrow union types? If your function logic can work most of the time on union type, it's great. But sooner or later you'll need to narrow it down to a specific . There are a few common patterns when narrowing union type. union member keyword Using typeof The keyword is the most basic TypeScript tool. Unfortunately, it will work only with , or typeof string number function function getDateFullYear(date: number | Date) { if (typeof date === "number") { return new Date(date).getFullYear(); } return date.getFullYear(); } keyword Using instanceof While works great with primitives, is great for the OOP feature of TypeScript — classes. typeof instanceof class Developer { public develop() { // ... } } class Manager { public manage() { // ... } } function work(person: Developer | Manager) { if (person instanceof Developer) { person.develop(); } else if (person instanceof Manager) { person.manage(); } } There is more OOP way of implementing function, but the above example should do the job as well. work or statement Using if switch Because union types can also consist of literal type members, not generic types but specific values, it's easy to use or statements on them. switch if function getTextColor(theme: "dark" | "light") { switch (theme) { case "dark": return "#ffffff"; case "light": return "#000000"; } } const textColor = getTextColor("darkk"); // 🛑 Argument of type '"darkk"' is not assignable to parameter of type '"dark" | "light"'.(2345) String literals are helpful for specifying a limited set of possible options, similar to an enum being a great replacement for them, as there is not that much added complexity as in the enum's case. Using union type of string literals will help not make typos or pass generic . string When you need to narrow type down from string to string literal, you can use a type guard function, which we'll discuss later in this post! Using “pattern match” object When talking about string or number literals, there is a great trick allowing you to achieve "pattern matching" in TypeScript: function getTextColor(theme: "dark" | "light") { return { dark: "#fff", light: "#000", }[theme]; } At first, it may look noisy, but the advantage of this solution is the fact it's an expression, not a statement, which may be sometimes required in places like JSX. Using the type guard function One nice but advanced feature TypeScript provides us is the ability to define a custom function. By default, TypeScript provides us with built-in type guards like , keywords we discussed earlier. There is also which is handy when we need to handle either a single value or multiple values of the same type. type guard typeof instanceof Array.isArray() But sometimes it's required to write something more specific to our business logic. Let's take a look at a simple function that narrows string to or : any either dark light type Theme = "dark" | "light"; function isTheme(value: string): value is Theme { return value === "dark" || value === "light"; } function getTheme(value: string): Theme { if (isTheme(value)) { return value; } // default case return "dark"; } This is helpful when your value is coming from the outside world (API or used provided) and you cannot be sure it will be always within your expected range. Not only primitive types Union types are not limited to primitive types or type literals. They can as well be objects. I'm using the following pattern all the time as TypeScript's equivalent of . It's a great pattern to express values that may contain different payloads or the same payload interpreted differently. algebraic data type (ADT) type Event = Credit | Debit; type Credit = { type: "credit"; amount: number }; type Debit = { type: "debit"; amount: number }; let account = 0; function handleAccountEvent(event: Event) { switch (event.type) { case "credit": account += event.amount; break; case "debit": account -= event.amount; break; } } handleAccountEvent({ type: "credit", amount: "10" }); // account == 10 handleAccountEvent({ type: "debit", amount: "5" }); // account == 5 Conclusion I hope you understand union types better! With all that knowledge and all the TypeScript features now under your belt, you can take advantage of them when working on the next great feature! Resources List of resources I used when researching this blog post: https://en.wikipedia.org/wiki/Union_(set_theory) https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types https://basarat.gitbook.io/typescript/type-system/discriminated-unions https://camchenry.com/blog/typescript-union-type Also Published here