Suggest an editImprove this articleRefine the answer for “Generic without extends”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)A generic without `extends` (for example `function identity<T>(value: T): T`) means `T` can be absolutely any type, so the compiler doesn't know what properties or methods it has. **Key point:** if a generic is unconstrained, the developer cannot safely access properties of type `T`, which often tempts the use of `as any` and makes the code unsafe.Shown above the full answer for quick recall.Answer (EN)Image## 1. What "generic without `extends`" means When you declare a generic like this: ```javascript function identity<T>(value: T): T { return value; } ``` you're telling TypeScript: > "`T` can be **absolutely any type**." And this is really true: `T` can be a number, a string, an object, an array, a function, `null`, `undefined`, `void`, `never`, anything. --- ## 2. What's the problem? The problem isn't the generic itself, it's the **assumptions** the developer makes about type `T`. Let's look at an example: ```javascript function getLength<T>(value: T): number { return value.length; // Error: T might not have length! } ``` TypeScript complains because `T` can be anything, even `number` or `boolean`, and then `length` doesn't exist. --- ## Why this is unsafe If TypeScript **didn't check** this, you could write code like this: ```javascript function unsafeLength<T>(value: T): number { return (value as any).length; } console.log(unsafeLength(123)); // undefined console.log(unsafeLength(true)); // undefined ``` The code compiles, but the behavior is **unpredictable**, runtime errors are guaranteed. TypeScript no longer protects you. --- ## 3. How to fix it: add `extends` You can **constrain the generic** so it only fits certain types: ```javascript function getLength<T extends { length: number }>(value: T): number { return value.length; // safe } ``` Now `T` must be an object (or an array, a string, and so on) that is **guaranteed to have** a `length` property. It works: ```javascript getLength("hello"); // 5 getLength([1, 2, 3]); // 3 ``` It doesn't work: ```javascript getLength(42); // Error - number has no length ``` > Thanks to `extends`, TypeScript **knows** which properties can be used. --- ## 4. An example of an unsafe generic without `extends` ```javascript function merge<T, U>(a: T, b: U): T & U { return { ...a, ...b }; } merge(1, "test"); // Logically meaningless, but TS doesn't forbid it ``` > TypeScript doesn't know that `T` and `U` are supposed to be objects, > and it allows you to pass numbers, strings, and even `null`. --- A safe version: ```javascript function merge<T extends object, U extends object>(a: T, b: U): T & U { return { ...a, ...b }; } merge({ name: "Tim" }, { age: 25 }); // OK merge(1, "test"); // Error - not an object ``` Now TypeScript strictly tracks the data structure. --- ## 5. Another example: with keys Without `extends`, it's easy to "break" the type logic: ```javascript function getValue<T, K>(obj: T, key: K) { return obj[key]; // Error: T might not have property K } ``` The correct way: constrain `K`: ```javascript function getValue<T, K extends keyof T>(obj: T, key: K) { return obj[key]; // safe } getValue({ name: "Tim", age: 25 }, "name"); // OK getValue({ name: "Tim" }, "invalid"); // Error - no such key ``` > Thanks to `extends keyof T`, TypeScript knows > that `key` must be an **existing property** of the object. --- ## 6. Why this matters If a generic is unconstrained (`T` without `extends`): - you cannot safely use properties or methods of that type; - TypeScript doesn't know which operations are allowed; - there's a temptation to "plug" types with `as any`, which makes the code unsafe. --- ## 7. Rule of thumb | Situation | What to do | | --- | --- | | You use a generic but don't access properties | `function identity<T>(x: T): T` - fine | | You use properties of the type (`.length`, `.id`, etc.) | Add `extends { length: number }` | | You use object keys | Add `K extends keyof T` | | You expect the generic to be an object | Add `extends object` | | You want to restrict to interface implementers | Add `extends MyInterface` | --- ## Summary | Without `extends` | With `extends` | | --- | --- | | `T` can be *any* type | `T` is constrained to a specific structure | | The compiler doesn't know which properties exist | The compiler checks allowed properties | | Runtime errors are possible | Errors are caught at compile time | | Often requires `as any` | Rarely requires `as` | | Less predictable code | Safe and self-documenting code | --- **Put simply:** > A generic without `extends` is a "universal container with no restrictions". > Without restrictions, TypeScript cannot protect you. > > Add `extends` when a generic must satisfy a **specific contract** (a structure, an interface, or keys).For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.