TypeScript - Union
TypeScript - Union Types
Section titled “TypeScript - Union Types”Union types allow you to define a variable or function parameter that can hold values of more than one specific type. They provide flexibility while still maintaining a degree of type safety, as the value must be one of the types listed in the union.
A union type is created using the pipe symbol (|) between two or more type annotations.
Syntax
Section titled “Syntax”let variableName: Type1 | Type2 | Type3 | ...;Example: Union Type Variable
Section titled “Example: Union Type Variable”let identifier: string | number;
identifier = 12345; // OKconsole.log(`Numeric identifier: ${identifier}`);
identifier = "user-abc-123"; // OKconsole.log(`String identifier: ${identifier}`);
// identifier = true; // Error: Type 'boolean' is not assignable to type 'string | number'.In this example, identifier can hold either a string or a number.
Working with Union Types
Section titled “Working with Union Types”When you have a value of a union type, TypeScript will only allow you to access members (properties or methods) that are common to all types in the union without performing a type check first.
function printValue(value: string | number) { // console.log(value.toUpperCase()); // Error: Property 'toUpperCase' does not exist on type 'string | number'. Property 'toUpperCase' does not exist on type 'number'. // console.log(value.toFixed(2)); // Error: Property 'toFixed' does not exist on type 'string | number'. Property 'toFixed' does not exist on type 'string'.
// toString() is common to both string and number (via prototype chain), so this is allowed: console.log(value.toString());}Narrowing Union Types with Type Guards
Section titled “Narrowing Union Types with Type Guards”To work with type-specific members, you need to narrow the union type down to a specific type within a certain code block. This is achieved using Type Guards.
Common type guards include:
typeofchecks: For primitive types likestring,number,boolean,symbol,bigint,undefined,function.instanceofchecks: For checking if an object is an instance of a specific class.- Property presence checks (
inoperator): Checking if an object has a specific property. - Equality checks: Comparing against specific literal values or
null/undefined. - Custom Type Guard Functions: Functions that return a type predicate (
parameterName is Type).
Example: Union Type and Function Parameter with Type Guards
Section titled “Example: Union Type and Function Parameter with Type Guards”function processInput(input: string | string[] | null) { if (typeof input === 'string') { // Here, TypeScript knows 'input' is a string console.log(`Processing string: ${input.toUpperCase()}`); } // Using Array.isArray for array check (better than typeof which returns 'object') else if (Array.isArray(input)) { // Here, TypeScript knows 'input' is a string[] console.log(`Processing array: Found ${input.length} items.`); input.forEach((item, index) => console.log(` Item ${index}: ${item}`)); } // Checking for null explicitly else if (input === null) { console.log("Input is null."); } // Note: No else needed here if null is the only remaining option}
processInput("hello");console.log("---");processInput(["Apple", "Banana", "Cherry"]);console.log("---");processInput(null);Union Types with Arrays and Objects
Section titled “Union Types with Arrays and Objects”Union types can be applied to array elements or object properties.
Example: Array of Union Types
Section titled “Example: Array of Union Types”To allow an array to contain elements of different types from the union, use parentheses:
// Array that can hold strings OR numberslet mixedArray: (string | number)[] = [1, "two", 3, "four"];
mixedArray.push(5);mixedArray.push("six");// mixedArray.push(true); // Error: Argument of type 'boolean' is not assignable to parameter of type 'string | number'.
console.log("Mixed Array:", mixedArray);
// Process mixed array using type guardsmixedArray.forEach(item => { if (typeof item === 'string') { console.log(`String item: ${item.toUpperCase()}`); } else { console.log(`Number item: ${item.toFixed(1)}`); }});Example: Union Type for Array Type
Section titled “Example: Union Type for Array Type”This defines a variable that can hold EITHER an array of numbers OR an array of strings, but not a mix of both in the same array.
let list: number[] | string[];
list = [1, 2, 3, 4]; // OK - Array of numbersconsole.log("Numeric Array:", list);
list = ["a", "b", "c"]; // OK - Array of stringsconsole.log("String Array:", list);
// list = [1, "a"]; // Error: Type '(string | number)[]' is not assignable to type 'number[] | string[]'. // Type '(string | number)[]' is not assignable to type 'string[]'.Literal Union Types
Section titled “Literal Union Types”Union types can be combined with literal types to restrict values to a specific set of constants.
type Alignment = "left" | "right" | "center";
let textAlign: Alignment;
textAlign = "center"; // OKtextAlign = "left"; // OK// textAlign = "justify"; // Error: Type '"justify"' is not assignable to type 'Alignment'.Union types are a powerful feature for modeling situations where a value can legitimately be one of several types, enhancing code flexibility while guiding developers to handle each possibility correctly using type guards.