Advanced TypeScript: Generics, Utility Types, and Type Guards
Comments
Sign in to join the conversation
Sign in to join the conversation
TypeScript has evolved from a simple linter to a Turing-complete type system. While basic types (string, number, interface) cover 80% of use cases, the remaining 20% requires powerful features to keep your codebase DRY and type-safe. Let's explore the advanced capabilities.
Generics allow you to create reusable components that work with a variety of types rather than a single one. It preserves the type information.
function identity<T>(arg: T): T {
return arg;
}
let output = identity<string>("myString"); // Type is string
Sometimes you want to limit the kinds of types that can be passed.
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // Now we know it has a .length property
return arg;
}
The keyof operator takes an object type and produces a string or numeric literal union of its keys.
interface Point {
x: number;
y: number;
}
type P = keyof Point; // "x" | "y"
Mapped types allow you to create new types based on old ones by "mapping" over properties.
type ReadOnly<T> = {
readonly [P in keyof T]: T[P];
};
This is where TS gets powerful. T extends U ? X : Y.
type TypeName<T> =
T extends string ? "string" :
T extends number ? "number" :
T extends boolean ? "boolean" :
T extends undefined ? "undefined" :
"object";
infer KeywordWithin a conditional type, you can declare a type variable using infer to capture a type.
Imagine you want to extract the return type of a function:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
Type guards allow you to narrow down the type of an object within a conditional block.
interface Fish { swim: () => void; }
interface Bird { fly: () => void; }
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined;
}
// Usage
if (isFish(pet)) {
pet.swim(); // TS knows pet is Fish here
}
Advanced TypeScript is about building robust libraries and abstractions. When you master generics, keyof, and conditional types, you can write code that is extremely flexible yet strictly validated, converting runtime errors into compile-time errors.