Typescript Foundations / Generics

Constraints

Constraints restrict what kinds of types can be used as arguments for a generic type.

You use extends to apply constraints, just like you would when extending interfaces.


✅ Why Use Constraints?

Without constraints, TypeScript allows any type, which can lead to type errors. Constraints ensure:

  • Only specific types are allowed.

  • Code completion and type inference improve.


🧪 Basic Syntax

function getLength<T extends { length: number }>(item: T): number {
  return item.length;
}

getLength("hello");         // ✅ OK (string has length)
getLength([1, 2, 3]);       // ✅ OK (array has length)
getLength({ length: 10 });  // ✅ OK
// getLength(123);          // ❌ Error: number has no 'length'

🔐 Constraining to Object with Specific Property

interface HasId {
  id: number;
}

function getId<T extends HasId>(item: T): number {
  return item.id;
}

getId({ id: 1, name: "Tisha" }); // ✅
getId({ id: 42 });               // ✅
// getId({ name: "No ID" });     // ❌ Error

📌 Constraining with Class Types

class Animal {
  name: string = "";
}

class Dog extends Animal {
  breed: string = "";
}

function createInstance<T extends Animal>(ctor: new () => T): T {
  return new ctor();
}

const dog = createInstance(Dog);

🔑 Using keyof in Constraints

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

const user = { name: "Tisha", age: 21 };
getProperty(user, "name"); // ✅ OK
// getProperty(user, "email"); // ❌ Error: 'email' not in user

K extends keyof T ensures that K is a valid key of object T.


🔁 Generic Classes with Constraints

interface Product {
  id: number;
  name: string;
}

class ProductManager<T extends Product> {
  private products: T[] = [];

  add(product: T) {
    this.products.push(product);
  }

  getAll(): T[] {
    return this.products;
  }
}


🧠 Summary

Constraint Type

Syntax Example

Property constraint

T extends { length: number }

Interface constraint

T extends HasId

Class constraint

T extends Animal

Key constraint

K extends keyof T