# Advanced Types ## Generic Constraints ```typescript // Basic constraint function getProperty(obj: T, key: K): T[K] { return obj[key] } // Multiple constraints interface HasId { id: number } interface HasName { name: string } function merge(obj1: T, obj2: U): T & U { return { ...obj1, ...obj2 } } // Generic constraint with default type ApiResponse = { success: true; data: T } | { success: false; error: E } // Constraint with infer type UnwrapPromise = T extends Promise ? U : T type Result = UnwrapPromise> // string ``` ## Conditional Types ```typescript // Basic conditional type type IsString = T extends string ? true : false // Distributive conditional types type ToArray = T extends any ? T[] : never type StringOrNumberArray = ToArray // string[] | number[] // Non-distributive (use tuple) type ToArrayNonDist = [T] extends [any] ? T[] : never type BothArray = ToArrayNonDist // (string | number)[] // Nested conditionals for type extraction type Flatten = T extends Array ? (U extends Array ? Flatten : U) : T type Nested = Flatten // string // Exclude null/undefined type NonNullable = T extends null | undefined ? never : T ``` ## Mapped Types ```typescript // Basic mapped type type ReadOnly = { readonly [K in keyof T]: T[K] } // Optional properties type Partial = { [K in keyof T]?: T[K] } // Required properties type Required = { [K in keyof T]-?: T[K] // Remove optional modifier } // Key remapping with 'as' type Getters = { [K in keyof T as `get${Capitalize}`]: () => T[K] } interface Person { name: string age: number } type PersonGetters = Getters // { getName: () => string; getAge: () => number; } // Filtering keys type PickByType = { [K in keyof T as T[K] extends U ? K : never]: T[K] } type StringFields = PickByType // { name: string } ``` ## Template Literal Types ```typescript // Basic template literal type EmailLocale = "en" | "es" | "fr" type EmailType = "welcome" | "reset-password" type EmailTemplate = `${EmailLocale}_${EmailType}` // 'en_welcome' | 'en_reset-password' | 'es_welcome' | ... // Intrinsic string manipulation type Uppercase = intrinsic type Lowercase = intrinsic type Capitalize = intrinsic type Uncapitalize = intrinsic type EventName = `on${Capitalize}` type ClickEvent = EventName<"click"> // 'onClick' // Template literal with mapped types type CSSProperties = { [K in "color" | "background" | "border" as `--${K}`]: string } // { '--color': string; '--background': string; '--border': string } // Pattern matching with infer type ExtractRouteParams = T extends `${infer _Start}/:${infer Param}/${infer Rest}` ? Param | ExtractRouteParams<`/${Rest}`> : T extends `${infer _Start}/:${infer Param}` ? Param : never type Params = ExtractRouteParams<"/users/:id/posts/:postId"> // 'id' | 'postId' ``` ## Higher-Kinded Types (Simulation) ```typescript // Type-level function simulation interface TypeClass { map: (f: (a: A) => B, fa: any) => any } // Functor pattern type Maybe = { type: "just"; value: T } | { type: "nothing" } const MaybeFunctor: TypeClass> = { map: (f: (a: A) => B, ma: Maybe): Maybe => { return ma.type === "just" ? { type: "just", value: f(ma.value) } : { type: "nothing" } }, } // Builder pattern with generics type Builder = { with

>(key: P, value: T[P]): Builder build(): K extends keyof T ? T : never } ``` ## Recursive Types ```typescript // JSON type type JSONValue = string | number | boolean | null | JSONValue[] | { [key: string]: JSONValue } // Deep partial type DeepPartial = T extends object ? { [K in keyof T]?: DeepPartial } : T // Deep readonly type DeepReadonly = T extends object ? { readonly [K in keyof T]: DeepReadonly } : T // Path type for nested objects type PathsToProps = T extends object ? { [K in keyof T]: K extends string ? T[K] extends object ? K | `${K}.${PathsToProps}` : K : never }[keyof T] : never interface User { profile: { name: string settings: { theme: string } } } type UserPaths = PathsToProps // 'profile' | 'profile.name' | 'profile.settings' | 'profile.settings.theme' ``` ## Variance and Contravariance ```typescript // Covariance (return types) type Producer = () => T let stringProducer: Producer = () => "hello" let objectProducer: Producer = stringProducer // OK: string is object // Contravariance (parameter types) type Consumer = (value: T) => void let objectConsumer: Consumer = (obj) => console.log(obj) let stringConsumer: Consumer = objectConsumer // OK in strict mode // Invariance (mutable properties) interface Box { value: T setValue(v: T): void } let stringBox: Box = { value: "", setValue: (v) => {} } // let objectBox: Box = stringBox; // Error: invariant ``` ## Type-Level Programming ```typescript // Type-level addition (limited) type Length = T["length"] type Concat = [...A, ...B] // Type-level conditionals type If = Condition extends true ? Then : Else // Type-level equality type Equal = (() => T extends X ? 1 : 2) extends () => T extends Y ? 1 : 2 ? true : false // Assert equal types (for testing) type Assert = T type Test = Assert> // OK ``` ## Quick Reference | Pattern | Use Case | | --------------------- | --------------------------- | | `T extends U ? X : Y` | Conditional type logic | | `infer R` | Extract types from patterns | | `K in keyof T` | Iterate over object keys | | `as NewKey` | Remap keys in mapped types | | Template literals | String pattern types | | `T extends any` | Distributive conditionals | | `[T] extends [any]` | Non-distributive check | | `-?` modifier | Remove optional | | `readonly` modifier | Make immutable |