Generic Constraints and keyof
While generics can accept any type, there are times when you need to write a generic function that requires a minimum set of properties. To do this, we use Generic Constraints.
1. Using extends for Constraints
Suppose you want a function that logs the length of an object. If you use a free generic T, the compiler raises an error because it cannot guarantee the object contains a length property.
// This fails compilation:
// function logLength<T>(arg: T) {
// console.log(arg.length);
// }We can fix this by creating an interface that describes our requirement and using the extends keyword to constrain our type variable:
interface Lengthwise {
length: number;
}
function logLength<T extends Lengthwise>(arg: T): void {
console.log(arg.length); // Now safe to access
}
logLength("hello"); // Valid (strings have a length property)
logLength([1, 2, 3]); // Valid (arrays have a length property)
// logLength(42); // Error: Argument of type 'number' is not assignable.2. The keyof Operator
The keyof operator takes an object type and produces a union of its keys (property names).
interface UserProfile {
id: string;
name: string;
email: string;
}
// UserKeys is "id" | "name" | "email"
type UserKeys = keyof UserProfile;3. Combining keyof and Constraints
You can combine generic constraints and the keyof operator to build highly type-safe helpers, such as a function that retrieves a property value from an object by its key.
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
const user = {
name: "Alice",
age: 28
};
const userName = getProperty(user, "name"); // Returns string
// getProperty(user, "email"); // Error: Argument of type '"email"' is not assignable.By using K extends keyof T, TypeScript prevents developers from passing non-existent property names.
4. Summary
- Use
T extends Interfaceto restrict generic type variables to shapes that include specific fields. - The
keyofoperator creates a union type containing all string and numeric keys of an object structure. - Combine
keyofand generic constraints to safely access object properties dynamically.