Mapped Types
Mapped types allow you to create new types based on the properties of an existing type. They are essential for transforming object structures dynamically.
type Optional<T> = {[P in keyof T]?: T[P];};
Hand-picked snippets across TypeScript, Python, Rust, Go, and more — each one comes with a line-by-line breakdown so you can read it like the people who wrote it.
Mapped types allow you to create new types based on the properties of an existing type. They are essential for transforming object structures dynamically.
type Optional<T> = {[P in keyof T]?: T[P];};
Conditional types select one of two possible types based on a condition expressed as a type relationship test.
type IsString<T> = T extends string ? "Yes" : "No";type Result = IsString<number>; // "No"
Intersection types combine multiple types into one, allowing you to merge existing types to create a type that has all the features you need.
type Admin = { privileges: string[] };type User = { name: string };type SuperUser = Admin & User;const boss: SuperUser = {name: "Alice",privileges: ["all"]};
Discriminated unions use a common literal property (the discriminant) to allow TypeScript to narrow down members of a union safely.
interface Circle { kind: "circle"; radius: number; }interface Square { kind: "square"; side: number; }type Shape = Circle | Square;function getArea(s: Shape) {if (s.kind === "circle") return Math.PI * s.radius ** 2;return s.side ** 2;}
Using 'keyof' with generics ensures that a function parameter is a valid key of a specific object, providing full type safety and IDE autocompletion.
function getProperty<T, K extends keyof T>(obj: T, key: K) {return obj[key];}const user = { id: 1, name: "Bob" };const userName = getProperty(user, "name");
Index signatures allow objects to have flexible keys that aren't known ahead of time. You define the type of the key (usually string or number) and the type of the value it returns.
interface StringConfig {[key: string]: string | number;id: string;version: number;}const config: StringConfig = {id: "A1",version: 1.2,theme: "dark",retries: 5};
Abstract classes cannot be instantiated directly. They serve as templates, allowing you to define shared methods while forcing subclasses to implement specific 'abstract' logic.
abstract class Shape {constructor(public color: string) {}abstract getArea(): number;printColor() {console.log(`Color: ${this.color}`);}}class Circle extends Shape {constructor(color: string, private radius: number) {super(color);}getArea() { return Math.PI * this.radius ** 2; }}
A type guard is a function that returns a type predicate ('pet is Fish'). It allows TypeScript to narrow down the type of an object within a specific code block after a runtime check.
interface Bird { fly: () => void; }interface Fish { swim: () => void; }function isFish(pet: Bird | Fish): pet is Fish {return (pet as Fish).swim !== undefined;}function move(pet: Bird | Fish) {if (isFish(pet)) {pet.swim(); // TypeScript knows it's a Fish} else {pet.fly(); // TypeScript knows it's a Bird}}