Learn how to combine types using unions and narrow wide types safely using typeof, instanceof, and in operator guards.
Discover how TypeScript infers types automatically and how let versus const declarations shape wide types versus narrow literal types.
A Union Type (|) allows a variable or parameter to accept one of several possible data types.
type ID = string | number;
function printID(id: ID) {
console.log(`ID is: ${id}`);
}
printID(101); // Valid
printID("usr_99"); // Valid
When working with a union type, TypeScript only allows operations that are valid on ALL union members. To perform type-specific logic, you must narrow the wide union down to a specific concrete type using runtime type guards.
typeof Guard: Narrows primitive types (string, number, boolean).instanceof Guard: Narrows class instances and built-in objects (Date, Error).in Operator Guard: Checks if a property key exists on an object.function formatPadding(padding: string | number): string {
// typeof guard narrowing
if (typeof padding === "number") {
return `${padding}px`; // Inside this block, padding is type 'number'!
}
return padding.trim(); // Inside this block, padding is type 'string'!
}
function processDate(input: Date | string): number {
// instanceof guard narrowing
if (input instanceof Date) {
return input.getTime();
}
return new Date(input).getTime();
}
id.toUpperCase() on a string | number union without a typeof check throws a compile error because .toUpperCase() does not exist on number.Use type guards to narrow unions safely. Next, let me explain Optional Properties, Strict Null Checks, and non-null handling!