DevAcademy
LearnTypeScriptGeneric Constraints
IntermediateTypeScript

Generic Constraints

Learn how to restrict a generic type parameter to types with specific properties using extends.

Reading Time

16 min

Lesson

Lesson 20 of 30

The Problem: Unconstrained Generics

A plain generic type parameter T could be anything, so TypeScript won’t let you access any properties on it — even ones that seem obviously safe, like .length.

An Unconstrained Generic Fails

function printLength<T>(value: T) {
  console.log(value.length); // Error: Property 'length' does not exist on type 'T'
}

Constraining with extends

Adding extends after the type parameter restricts T to types that satisfy a given shape, unlocking access to the properties that shape guarantees.

A Constrained Generic

interface HasLength {
  length: number;
}

function printLength<T extends HasLength>(value: T) {
  console.log(value.length); // OK — T is guaranteed to have 'length'
}

printLength("hello");        // OK — strings have .length
printLength([1, 2, 3]);      // OK — arrays have .length
printLength(42);              // Error: number doesn't have .length

Constraining to keyof Another Type

A very common pattern constrains one generic parameter to be a key of another, guaranteeing safe, typed property access — this is exactly how the built-in Object methods stay type-safe.

A Typed getProperty Function

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const user = { name: "Alice", age: 30 };

getProperty(user, "name"); // OK, returns a string
getProperty(user, "email"); // Error: 'email' is not a key of the user object

Default Type Parameters

A generic parameter can have a default type, used when the caller doesn’t explicitly provide or infer one.

Default Generic Type

interface ApiResponse<T = unknown> {
  data: T;
  success: boolean;
}

const response: ApiResponse = { data: "anything", success: true }; // T defaults to unknown

Constraints Narrow, They Don’t Widen

A constraint only guarantees the minimum shape T must have — the actual type passed in can still have additional properties beyond what the constraint requires.

Best Practice

Reach for constraints as soon as a generic function needs to access any property on its parameter. The keyof pattern (T, K extends keyof T) is especially useful for writing safe, reusable object utilities.

Interview Questions

Quick Quiz

1. Why does an unconstrained generic <T> not allow accessing value.length?

2. What does <T extends HasLength> do?

3. What does K extends keyof T typically guarantee in a function signature?