- TypeScript Tutorial
- TypeScript Home
- TypeScript Introduction
- TypeScript Setup
- TypeScript First Program
- TypeScript vs JavaScript
- TypeScript Data Types
- TypeScript Type Inference
- TypeScript Type Annotations
- TypeScript Interfaces
- TypeScript Enums
- TypeScript Type Aliases
- TypeScript Type Assertions
- TypeScript Variables
- TypeScript Functions
- TypeScript Functions
- TypeScript Optional Parameters
- TypeScript Default Parameters
- TypeScript Rest Parameters
- TypeScript Arrow Functions
- Classes and Objects
- Introduction to Classes
- Properties and Methods
- Access Modifiers
- Static Members
- Inheritance
- Abstract Classes
- Interfaces vs Classes
- Advanced Types
- TypeScript Union Types
- TypeScript Intersection Types
- TypeScript Literal Types
- TypeScript Nullable Types
- TypeScript Type Guards
- TypeScript Discriminated Unions
- TypeScript Index Signatures
- TypeScript Generics
- Introduction to Generics
- TypeScript Generic Functions
- TypeScript Generic Classes
- TypeScript Generic Constraints
- TypeScript Modules
- Introduction to Modules
- TypeScript Import and Export
- TypeScript Default Exports
- TypeScript Namespace
- Decorators
- Introduction to Decorators
- TypeScript Class Decorators
- TypeScript Method Decorators
- TypeScript Property Decorators
- TypeScript Parameter Decorators
- Configuration
- TypeScript tsconfig.json File
- TypeScript Compiler Options
- TypeScript Strict Mode
- TypeScript Watch Mode
Union Types in TypeScript
Union types in TypeScript allow a variable to hold values of multiple types. This feature provides flexibility when dealing with data that can be of different types, enabling better type safety and more precise type definitions.
Key Concepts of Union Types
- Definition: A union type is a way to define a variable that can hold more than one type. It is created by separating the types with a pipe (
|
). - Use Case: Union types are useful when you expect a value to be one of several types, but not necessarily always a single type.
- Type Safety: TypeScript ensures type safety by checking which type the variable holds at compile-time, so you can use the correct methods or properties based on the type.
Example Usage of Union Types
Example 1: Basic Union Type
let value: string | number;
value = "Hello"; // Valid
value = 42; // Valid
value = true; // Error: Type 'boolean' is not assignable to type 'string | number'
In this example:
- The variable
value
can be either astring
or anumber
. - Attempting to assign a
boolean
results in an error because it's not part of the union.
Example 2: Union Type with Functions
function printId(id: string | number) {
if (typeof id === "string") {
console.log(`String ID: ${id}`);
} else {
console.log(`Number ID: ${id}`);
}
}
printId(101); // Output: Number ID: 101
printId("abc123"); // Output: String ID: abc123
Here, the function printId
accepts either a string
or a number
. By using a type guard (typeof
), the correct branch is executed based on the actual type of id
.
Example 3: Union Type with Objects
type Admin = {
role: string;
permissions: string[];
};
type User = {
username: string;
email: string;
};
let person: Admin | User;
person = { role: "Admin", permissions: ["read", "write"] }; // Valid
person = { username: "john_doe", email: "[email protected]" }; // Valid
person = { age: 30 }; // Error: Type '{ age: number; }' is not assignable to type 'Admin | User'
In this case, the person
variable can be either an Admin
or a User
object, with different properties. If a value doesn't match either structure, TypeScript raises an error.
Type Narrowing with Union Types
When using union types, TypeScript provides type narrowing to help you determine the type of a variable at runtime. This is often done with type guards.
Example: Type Guard with typeof
function formatValue(value: string | number): string {
if (typeof value === "string") {
return `String: ${value}`;
} else {
return `Number: ${value}`;
}
}
console.log(formatValue(123)); // Output: Number: 123
console.log(formatValue("abc")); // Output: String: abc
The typeof
operator helps to narrow down the type of value
within the if
statement, allowing TypeScript to provide accurate type inference.
Union Types with Array
Union types can also be used in arrays, where each element in the array can be of multiple types.
let values: (string | number)[] = ["apple", 42, "banana", 100];
values.push("orange"); // Valid
values.push(200); // Valid
values.push(true); // Error: Argument of type 'boolean' is not assignable to parameter of type 'string | number'
In this example, the values
array can hold both strings and numbers, but not other types like boolean
.
Using null
and undefined
with Union Types
You can include null
and undefined
in union types to handle cases where a value might be missing or not defined.
let name: string | null = null;
name = "John"; // Valid
name = null; // Valid
name = undefined; // Error: Type 'undefined' is not assignable to type 'string | null'
Here, the variable name
can either be a string
or null
. Attempting to assign undefined
would raise an error, as it's not part of the union.
Union Types with Custom Types
Union types can also be combined with custom types and interfaces to create more complex structures.
interface Cat {
type: "cat";
lives: number;
}
interface Dog {
type: "dog";
breed: string;
}
type Animal = Cat | Dog;
function describeAnimal(animal: Animal) {
if (animal.type === "cat") {
console.log(`This is a cat with ${animal.lives} lives.`);
} else {
console.log(`This is a dog of breed ${animal.breed}.`);
}
}
describeAnimal({ type: "cat", lives: 9 }); // Output: This is a cat with 9 lives.
describeAnimal({ type: "dog", breed: "Golden Retriever" }); // Output: This is a dog of breed Golden Retriever.
Here, the Animal
type is a union of two custom types: Cat
and Dog
. TypeScript uses the type
property to narrow down the type of the object and provide appropriate handling.
Summary
- Union Types allow a variable to hold multiple types, providing flexibility while maintaining type safety.
- You define a union type by using the pipe (
|
) symbol between types. - Type Narrowing helps TypeScript determine the exact type of a union at runtime, often with type guards like
typeof
. - Union types are useful when you expect a value to be one of several possible types, allowing for more general but safe handling of data.