Generic parameters can have default types (used when not explicitly specified or inferable) and can be constrained by an intersection of requirements.
ts
interface Identifiable { id: string; }
interface Timestamped { createdAt: number; }
function stamp<T extends Identifiable & Timestamped>(item: T): string {
return `${item.id}@${item.createdAt}`;
}
interface ApiResponse<T = unknown> {
data: T;
status: number;
}
const raw: ApiResponse = { data: "anything", status: 200 }; // T defaults to unknown
const typed: ApiResponse<{ balance: number }> = { data: { balance: 5 }, status: 200 };Combined constraints (`T extends A & B`) require the argument to satisfy every listed requirement simultaneously. Defaults are especially handy for library APIs where most callers don't care about the generic parameter but power users can still supply one.