TypeScript Generics Deep Dive: From Basics to Advanced Type Programming
A complete guide to TypeScript generics — generic functions, interfaces, constraints, conditional types, mapped types, template literal types, and building reusable utility types for production codebases.

Why Generics Are the Key to Reusable TypeScript#
Generics are the mechanism by which TypeScript allows you to write code that works across multiple types while preserving type safety. Without generics, you face a choice between code that is either type-safe but duplicated, or reusable but typed as any (which defeats the purpose of TypeScript).
Mastering generics is the step that separates developers who use TypeScript as "JavaScript with occasional type annotations" from those who use TypeScript's full type system to catch bugs at the structural level.
Generic Functions: The Foundation#
A generic function accepts a type parameter — written as — that is determined by the types of the arguments passed. This allows the function to be reusable across types while remaining type-safe.
The simplest example: an identity function that returns its input. Without generics, you'd type this as any. With generics: function identity. When called with a string, TypeScript infers T = string. When called with a number, T = number.
Practical Real-World Example: API Response Wrapper A generic `ApiResponse<T>` type can wrap any data type with consistent error handling structure:
type ApiResponse<T> = { data: T; status: number; error: string | null }Now ApiResponse is perfectly typed, as is ApiResponse — without duplicating the wrapper structure.
Generic Constraints: `extends`#
Constraints restrict what types a generic can accept. The extends keyword limits the type parameter to types that satisfy a specific structure.
Example: A getProperty function that accepts any object and a key of that object:
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K]The K extends keyof T constraint ensures the key must exist on the object — TypeScript will catch typos and invalid key names at compile time.
Practical Use: Sorting Function with Required Property A generic sort function that works on any array of objects with a numeric `id` field: `<T extends { id: number }>` ensures you can access `.id` safely inside the function.
Conditional Types#
Conditional types allow type expressions that depend on other types: T extends U ? X : Y. This is TypeScript's equivalent of an if-else at the type level.
NonNullable=T extends null | undefined ? never : TReturnType=T extends (...args: any) => infer R ? R : any
The infer keyword is used within conditional types to extract parts of a type.
Practical Use: Unwrapping Promise Types
type Awaited<T> = T extends Promise<infer R> ? R : TAwaited resolves to string. This is how TypeScript's built-in Awaited utility type works.
Mapped Types#
Mapped types transform existing types by iterating over their properties. Using { [K in keyof T]: ... } syntax:
Readonly:{ readonly [K in keyof T]: T[K] }— makes all properties read-onlyPartial:{ [K in keyof T]?: T[K] }— makes all properties optionalRecord:{ [P in K]: V }— creates a type with keys K and values V
Building a Custom Mapped Type: Nullable
type Nullable<T> = { [K in keyof T]: T[K] | null }Nullable creates a type where every User property can also be null — useful for form state where fields may not yet have values.
Template Literal Types#
Template literal types allow string manipulation at the type level:
type EventName<T extends string> = `on${Capitalize<T>}`
type ClickEvent = EventName<'click'> // 'onClick'This is used in libraries like Prisma and Vue to generate event handler names and API method names from base strings at compile time.
Essential Built-in Utility Types#
TypeScript ships with utility types that cover the most common type transformation needs:
Partial: All properties optionalRequired: All properties requiredReadonly: All properties read-onlyPick: Create type with only specified keys from TOmit: Create type with all keys from T except KExclude: Remove types assignable to U from union TExtract: Keep only types assignable to U from union TReturnType: Extract return type of a functionParameters: Extract parameter types of a function as a tupleAwaited: Unwrap Promise types recursively
Frequently Asked Questions#
Q: When should I use generics vs. union types? Use generics when the relationship between input and output types matters — the output type should depend on the input type. Use union types when a value can be any of a fixed set of types and the relationship between input and output is not relevant.
Q: What is the difference between any and unknown?
any disables type checking — you can do anything with an any value. unknown is type-safe — you must narrow the type (with typeof, instanceof, or a type guard) before using it. Always prefer unknown over any when the type is genuinely unknown.
Q: How do I debug complex generic type errors?
Break the type down into simpler pieces and hover over each part in your IDE to see what TypeScript infers. Using type Debug = YourComplexType and then checking the tooltip for Debug is often the most effective approach.

Published by
Vyuhantrix Team
TypeScript & Frontend Engineering · Vyuhantrix
Vyuhantrix is an open technology learning platform based in Ahmedabad, India, publishing step-by-step programming tutorials, system design breakdowns, and free developer tools.
Keep Learning
Recommended Guides
The Definitive Full-Stack Web Development Roadmap (2026 Edition)
A complete step-by-step masterclass covering modern HTML5/CSS, TypeScript, Next.js App Router, Server Components, API Design, and Cloud Edge Deployments.
Top 5 Programming Languages to Learn in 2026 for High-Impact Careers
Discover the most in-demand languages driving cloud infrastructure, AI development, web platforms, systems engineering, and enterprise backend systems.
Mastering React Server Components in Next.js 15: A Complete Guide
A deep dive into React Server Components, how they differ from Client Components, and how Next.js 15 leverages them to achieve zero-bundle-size rendering, streaming, and superior Core Web Vitals.