Generic Constraints & keyof Operator
Restrict generic type parameters using the extends keyword and inspect object keys using the keyof operator.
1. Generic Constraints (`extends`)
Sometimes you want generics to only accept types that have specific properties (like a length property):
interface Lengthwise {
length: number;
}
// T is constrained to types that have a .length property!
function logLength<T extends Lengthwise>(item: T): number {
console.log("Length is:", item.length);
return item.length;
}
logLength("Hello World"); // Works! String has .length
logLength([1, 2, 3, 4]); // Works! Array has .length
// ❌ Error: Argument of type 'number' is not assignable to 'Lengthwise'
// logLength(123);2. The `keyof` Operator
The keyof operator takes an object type and produces a union string literal of its key names:
interface User {
id: number;
name: string;
email: string;
}
// UserKeys is "id" | "name" | "email"
type UserKeys = keyof User;3. Safe Object Property Getter (`K extends keyof T`)
Combine generics with keyof to create type-safe helper functions that guarantee a key exists on an object:
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const person = { name: "Alice", age: 30, isDeveloper: true };
const userName = getProperty(person, "name"); // Type is string
const userAge = getProperty(person, "age"); // Type is number
// ❌ Error: Argument of type '"salary"' is not assignable to parameter of type '"name" | "age" | "isDeveloper"'
// getProperty(person, "salary");Next Up
Master built-in TypeScript utility types: Partial, Required, Readonly, Record, Pick, and Omit.
Next Lesson: Built-in Utility Types →