TypeScript Course
TypeScript
/
Advanced

Generic Constraints

Definition

Using the `extends` keyword within a generic type declaration to restrict the kinds of types that can be passed to a generic parameter.

Explain Like I'm New

Generics are great, but sometimes they are TOO flexible. If you build a generic function that prints the `.length` of an item, you want to allow Strings and Arrays, but NOT Numbers (numbers don't have a `.length` property). A Constraint acts as a bouncer, saying: 'I don't care what exact type you are, but you MUST at least have a .length property.'

Real World Example

Writing a generic function that updates a database record. The function takes any object, but it CONSTRAINS the object to ensure it MUST have an `id: string` property so the database knows what to update.

Common Use Cases

  • •Restricting overly broad generics
  • •Ensuring objects have required baseline properties

Interactive Example

// Define the baseline requirement
interface HasLength {
  length: number;
}

// T can be anything, AS LONG AS it has a 'length' property of type number
function logLength<T extends HasLength>(arg: T): void {
  console.log("Length is:", arg.length);
}

// Valid: Strings have .length
logLength("Hello World"); 

// Valid: Arrays have .length
logLength([1, 2, 3]); 

// Valid: Objects with a manual length property
logLength({ id: 1, length: 10 }); 

// ERROR: Argument of type 'number' does not satisfy constraint 'HasLength'.
// logLength(55);

Interview Questions

basic

  • What keyword is used to constrain a generic?

intermediate

  • What happens if you don't constrain a generic when accessing properties?

advanced

  • Can you constrain a generic to be a specific primitive, like a string or number?

Flash Cards

Question

What happens if you don't constrain?

Click to reveal answer
Answer

If you do `function logLength<T>(arg: T) { console.log(arg.length) }`, TypeScript will throw an error: 'Property length does not exist on type T'. Because `T` could be literally anything (even a Number), TS protects you. You must constrain it: `<T extends { length: number }>`.

Question

Can you constrain to primitives?

Click to reveal answer
Answer

Yes! `function process<T extends string | number>(val: T)` ensures nobody can pass an object or boolean into the generic function.