Generic Constraints

Setting minimum requirements for a generic type.

TypeScript5 min readConcept 24 of 54

The 'extends' keyword in Generics

By default, a generic <T> can be literally anything—a string, a number, a boolean, or an object.

If you try to access a property on T (like T.length), TypeScript will throw an error because it cannot guarantee that property exists. You have to constrain the generic using the extends keyword to set a minimum requirement.

Preserving the original type

Why not just write function logLength(arg: { length: number })? If you do that, and you pass a string[] to the function, the function's return type would become { length: number }. You lose the fact that it was an array!

By writing function logLength<T extends { length: number }>(arg: T): T, you guarantee the argument has a length property, BUT you return the exact original string[] type.

Syntax

typescript // T MUST be an object with an 'id' string property. function addTimestamp<T extends { id: string }>(obj: T) { return { ...obj, timestamp: Date.now() }; } // OK: This object has an 'id' string, plus extra properties. // The return type perfectly preserves the 'name' property! const user = addTimestamp({ id: "123", name: "Alice" }); // Error: Type 'number' does not satisfy the constraint '{ id: string }'. // addTimestamp(42);

Try it

Attempt to pass different types into the constrained generic function. Watch how the type checker acts as a gatekeeper based on the extends requirement.

function addTime<T extends { id: string }>
(arg: T): T & { time: number } {
return { ...arg, time: Date.now() };
}

// Calling the function
const res = addTime({ id: "123" });
Gatekeeper Constraint
Requirement: extends { id: string }

Accepted

The argument satisfies the minimum id requirement.

Return Type Result (T Preserved):
{ id: string } & { time: number }

Check yourself

Pick an answer to lock it in, then read why. Getting one wrong is part of how it sticks.

  1. 1If you call `function echo<T extends { name: string }>(arg: T): T` and pass `{ name: "Bob", age: 30 }`, what is the return type?

Remember this

  • Unconstrained generics <T> cannot have properties accessed safely.
  • Use <T extends Type> to enforce a minimum requirement on the generic.
  • Unlike directly typing the parameter, generic constraints preserve the exact original type of the argument (including extra properties).

Done with this concept?

Mark it complete to track your progress. No login needed.