0
0
Typescriptprogramming~15 mins

Why union types are needed in Typescript - Why It Works This Way

Choose your learning style9 modes available
Overview - Why union types are needed
What is it?
Union types in TypeScript allow a variable to hold more than one type of value. Instead of restricting a variable to a single type, union types let it be one of several types. This helps write flexible code that can handle different kinds of data safely. It is like saying, 'this can be either this type or that type.'
Why it matters
Without union types, programmers would have to write many separate functions or variables for each possible type, making code longer and harder to maintain. Union types solve this by letting one variable or function accept multiple types, reducing errors and improving code clarity. This flexibility is crucial in real-world programs where data can come in different forms.
Where it fits
Before learning union types, you should understand basic TypeScript types like string, number, and boolean. After union types, you can learn about advanced type features like intersection types, type guards, and discriminated unions to handle complex data safely.
Mental Model
Core Idea
Union types let a value be one of several types, combining flexibility with type safety.
Think of it like...
Imagine a mailbox that can accept letters or small packages. The mailbox is designed to hold either type, so it’s flexible but still knows what it can accept.
Value
  │
  ├─ Type A (e.g., string)
  ├─ Type B (e.g., number)
  └─ Type C (e.g., boolean)

Union Type = Type A | Type B | Type C
Build-Up - 6 Steps
1
FoundationBasic TypeScript Types
🤔
Concept: Learn simple types like string, number, and boolean.
In TypeScript, variables usually have one type. For example: let name: string = "Alice"; let age: number = 30; let isStudent: boolean = true; Each variable can only hold values of its declared type.
Result
Variables hold only one kind of value, preventing mistakes like assigning a number to a string variable.
Understanding basic types is essential because union types build on this idea by combining multiple types.
2
FoundationLimitations of Single Types
🤔
Concept: See why restricting variables to one type can be limiting.
Sometimes, a variable needs to hold different types of values. For example, a user ID might be a number or a string: // Without union types, you must choose one type: let userId: string = "123"; // But what if sometimes it's a number? This causes problems because the variable can't hold both types.
Result
You realize that single types can force awkward workarounds or unsafe code.
Knowing this limitation motivates the need for union types to handle multiple types safely.
3
IntermediateIntroducing Union Types
🤔Before reading on: do you think a variable can hold both a string and a number at the same time, or just one of them? Commit to your answer.
Concept: Union types allow a variable to be one of several types, but only one at a time.
You can declare a variable with union types like this: let userId: string | number; Now userId can hold either a string or a number: userId = "abc123"; // valid userId = 456; // also valid But it cannot hold both at once.
Result
Variables become flexible and safe, accepting multiple types without losing type checking.
Understanding that union types mean 'one of these types' helps prevent confusion about how values are stored.
4
IntermediateUsing Union Types in Functions
🤔Before reading on: do you think a function with union type parameters needs to handle all types explicitly, or can it treat them the same? Commit to your answer.
Concept: Functions can accept union types, but you often need to check the actual type inside the function.
Example: function printId(id: string | number) { if (typeof id === "string") { console.log("ID as string: " + id.toUpperCase()); } else { console.log("ID as number: " + id); } } printId("abc"); printId(123); TypeScript forces you to check the type before using type-specific methods.
Result
Functions become more flexible but require careful handling of each possible type.
Knowing you must check types inside functions prevents runtime errors and keeps code safe.
5
AdvancedType Narrowing with Union Types
🤔Before reading on: do you think TypeScript automatically knows the exact type inside a union, or do you need to help it? Commit to your answer.
Concept: TypeScript uses type narrowing to understand which type a union variable currently holds based on checks.
Type narrowing means TypeScript can tell the exact type after you check it: function process(value: string | number) { if (typeof value === "string") { // Here TypeScript knows value is string console.log(value.toLowerCase()); } else { // Here TypeScript knows value is number console.log(value.toFixed(2)); } } This helps avoid errors and gives better code completion.
Result
You get safer code and better developer experience with type-aware tools.
Understanding type narrowing is key to using union types effectively in real code.
6
ExpertUnion Types in Complex Type Systems
🤔Before reading on: do you think union types can combine with other advanced types like interfaces or literals? Commit to your answer.
Concept: Union types can combine with interfaces, literal types, and more to model complex data precisely.
Example: interface Cat { kind: "cat"; meow: () => void; } interface Dog { kind: "dog"; bark: () => void; } type Pet = Cat | Dog; function speak(pet: Pet) { if (pet.kind === "cat") { pet.meow(); } else { pet.bark(); } } This pattern is called discriminated unions and is powerful for real-world data.
Result
You can write very precise and safe code that handles many cases clearly.
Knowing how union types combine with other features unlocks advanced type-safe programming patterns.
Under the Hood
At runtime, union types do not exist as a separate entity; they are a compile-time feature. TypeScript uses union types to check code correctness before running it. The compiler ensures that variables declared with union types are only used in ways safe for all possible types or properly narrowed. This prevents many bugs without affecting the generated JavaScript, which runs normally.
Why designed this way?
Union types were introduced to balance flexibility and safety. Before union types, developers either used very loose types like 'any' (which lose safety) or wrote many overloads and checks manually. Union types provide a clear, concise way to express multiple possible types, improving code readability and maintainability while preserving type safety.
TypeScript Compiler
  │
  ├─ Checks variable usage against union types
  │    ├─ Ensures safe operations
  │    └─ Requires type narrowing when needed
  └─ Emits plain JavaScript without union types

Runtime JavaScript
  └─ Runs normally without type info
Myth Busters - 4 Common Misconceptions
Quick: Does a union type mean a variable holds all types at once, or just one? Commit to your answer.
Common Belief:A union type means the variable holds all the types simultaneously.
Tap to reveal reality
Reality:A union type means the variable holds exactly one of the types at a time, never multiple simultaneously.
Why it matters:Believing otherwise can cause confusion and incorrect assumptions about how data is stored and used, leading to bugs.
Quick: Can you use methods from all union types without checks? Commit to your answer.
Common Belief:You can call any method from any type in the union without checking the type first.
Tap to reveal reality
Reality:You must check the variable's type before using methods specific to one type; otherwise, TypeScript will give errors.
Why it matters:Ignoring this leads to runtime errors when calling methods that don't exist on the actual type.
Quick: Does union type checking happen at runtime? Commit to your answer.
Common Belief:Union types enforce type checks during program execution (runtime).
Tap to reveal reality
Reality:Union types are only checked at compile time; at runtime, JavaScript runs without type information.
Why it matters:Expecting runtime checks can cause false security; developers must still write safe runtime code.
Quick: Can union types replace all type safety needs? Commit to your answer.
Common Belief:Union types alone are enough to handle all type safety scenarios.
Tap to reveal reality
Reality:Union types are powerful but often need to be combined with type guards, discriminated unions, or other features for full safety.
Why it matters:Overreliance on union types without proper checks can lead to subtle bugs.
Expert Zone
1
Union types combined with literal types enable discriminated unions, which allow precise type narrowing based on a common property.
2
Excessive use of wide union types can make code harder to maintain and understand, so balancing flexibility and clarity is crucial.
3
TypeScript's control flow analysis smartly narrows union types in complex conditions, but understanding its limits helps avoid unexpected errors.
When NOT to use
Union types are not ideal when you need a value to hold multiple types simultaneously; in that case, use tuple types or arrays. Also, if the union becomes too broad, consider redesigning types for clarity. Alternatives include intersection types for combining features or generics for flexible yet constrained types.
Production Patterns
In real-world code, union types are used for API responses that can vary, event handlers accepting different event types, and UI components that accept multiple prop types. Discriminated unions are common for state machines and Redux reducers to handle different action types safely.
Connections
Polymorphism (Object-Oriented Programming)
Union types provide a type-safe way to handle multiple types, similar to how polymorphism allows objects of different classes to be treated uniformly.
Understanding union types helps grasp how different data types can be managed under a single interface, a core idea in polymorphism.
Set Theory (Mathematics)
Union types correspond to the union operation in set theory, where a set contains elements from multiple sets combined.
Recognizing this connection clarifies that union types represent a value belonging to one of several sets (types), not all simultaneously.
Natural Language Ambiguity (Linguistics)
Union types are like words with multiple meanings, where context determines the intended meaning.
This shows how programming types and language meaning both rely on context to resolve ambiguity safely.
Common Pitfalls
#1Trying to use methods from all union types without checking the actual type.
Wrong approach:function printLength(value: string | number) { console.log(value.length); // Error: number has no 'length' }
Correct approach:function printLength(value: string | number) { if (typeof value === 'string') { console.log(value.length); } else { console.log('Number has no length'); } }
Root cause:Misunderstanding that union types require type narrowing before using type-specific properties or methods.
#2Assuming union types check types at runtime.
Wrong approach:let value: string | number = 42; if (value instanceof String) { // This check won't work as expected }
Correct approach:let value: string | number = 42; if (typeof value === 'string') { // Correct type check }
Root cause:Confusing compile-time type checking with runtime type checks.
#3Using very broad union types without constraints, making code complex and error-prone.
Wrong approach:type Data = string | number | boolean | object | null | undefined; function process(data: Data) { // Hard to handle all cases safely }
Correct approach:type Data = string | number; function process(data: Data) { // Simpler and safer to handle }
Root cause:Not balancing flexibility with maintainability and clarity.
Key Takeaways
Union types let variables hold one of several types, increasing flexibility while keeping type safety.
They require type checks or narrowing inside code to safely use type-specific features.
Union types exist only at compile time; runtime JavaScript has no type information.
Combining union types with other TypeScript features enables powerful and precise type-safe code.
Misusing union types or ignoring type narrowing leads to common bugs and confusion.