Lesson 25 of 80
A plain generic accepts absolutely anything, which means you can't safely do much with it — extends is how you narrow that down to 'anything, as long as it has this shape.'
12 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 2
Why does `function getLength<T>(item: T) { return item.length; }` fail to compile without a constraint on T?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
An unconstrained generic function getLength<T>(item: T) can't safely access .length, because T could be anything, including something with no .length at all. A constraint narrows what T is allowed to be:
function getLength<T extends { length: number }>(item: T): number {
return item.length; // ✅ safe — every valid T is guaranteed to have .length
}
getLength("hello"); // ✅ strings have .length
getLength([1, 2, 3]); // ✅ arrays have .length
getLength(42); // ❌ number has no .length
T extends { length: number } doesn't mean "T is a subtype of that interface" in the class-inheritance sense — it means "T must be at least structurally compatible with that shape," the same structural-typing rule from earlier in this track, now applied to a generic parameter instead of a plain variable.
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { name: "Ada", age: 36 };
getProp(user, "name"); // ✅ typed as string
getProp(user, "email"); // ❌ "email" isn't a key of user
K extends keyof T ties the two generic parameters together: key must be one of T's actual keys — this is exactly the type-safe way to write a generic property-getter, impossible to call with a typo'd key name.
interface ApiResponse<T = unknown> { data: T; status: number }
const r: ApiResponse = { data: "anything", status: 200 }; // T defaults to unknown
function longest<T>(a: T, b: T) { return a.length > b.length ? a : b; } — error: T might not have .length at all.
<T extends { length: number }> still lets T be inferred as the specific, narrow type of whatever was actually passed (e.g. the literal array type), not widened to the constraint itself.getProp's K extends keyof T pattern is exactly how libraries type safe deep-object-access helpers — it's one of the most practically useful constraint patterns in real code, not just an academic example.<T = unknown> just says "if nothing is specified, use unknown"; you still often want <T extends SomeShape = DefaultShape> combining both when the type genuinely needs restricting too.K extends keyof T is one of the most common "prove you actually understand generics" patterns interviewers reach for — implementing a type-safe getProp/pick function from scratch is a great way to demonstrate it.