Bird
Raised Fist0
Typescriptprogramming~10 mins

Generic constraints with extends in Typescript - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Generic constraints with extends
Define generic type T
↓
Add constraint: T extends SomeType
↓
Use T in function/class
↓
Call function with argument
↓
Check if argument matches constraint
↓
Run code
This flow shows how a generic type T is constrained to extend a specific type, ensuring only compatible types are used.
Execution Sample
Typescript
interface HasName { name: string }
function greet<T extends HasName>(obj: T): string {
  return `Hello, ${obj.name}`;
}

const person = { name: "Alice", age: 30 };
console.log(greet(person));
This code defines a generic function that only accepts objects with a 'name' property, then greets the person.
Execution Table
StepActionEvaluationResult
1Define interface HasNameHasName requires 'name' stringInterface ready
2Define function greet with T extends HasNameT must have 'name' propertyFunction ready
3Create object person{ name: 'Alice', age: 30 }Object created
4Call greet(person)Check if person fits T extends HasNameperson has 'name', OK
5Return greeting string`Hello, Alice`Output: Hello, Alice
6Print outputConsole logs greetingHello, Alice
💡 Function call succeeds because person matches constraint HasName
Variable Tracker
VariableStartAfter 1After 2After 3After 4Final
personundefinedundefinedundefined{ name: 'Alice', age: 30 }{ name: 'Alice', age: 30 }{ name: 'Alice', age: 30 }
greet returnundefinedundefinedundefinedundefined`Hello, Alice``Hello, Alice`
Key Moments - 2 Insights
Why does greet(person) work even though person has an extra 'age' property?
Because the constraint only requires 'name' property. Extra properties do not cause errors as long as the required ones exist (see step 4 in execution_table).
What happens if we call greet with an object missing 'name'?
TypeScript will give a compile-time error because the object does not satisfy the constraint T extends HasName (not shown in execution_table but implied in flow).
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, what is the output at step 5?
A"Hello, Alice"
B"Hello, person"
C"Hello, undefined"
DError
💡 Hint
Check the 'Result' column at step 5 in execution_table
At which step does TypeScript check if the argument matches the constraint?
AStep 2
BStep 4
CStep 3
DStep 6
💡 Hint
Look at the 'Action' and 'Evaluation' columns in execution_table for step 4
If the object passed to greet did not have a 'name' property, what would happen?
AThe function would print 'Hello, undefined'
BThe function would run but return an empty string
CTypeScript would give a compile-time error
DThe function would ignore the missing property and run
💡 Hint
Refer to key_moments about constraint violations and TypeScript errors
Concept Snapshot
Generic constraints with extends:
- Use <T extends Type> to restrict T
- T must have all properties of Type
- Allows safe access to those properties
- Extra properties are allowed
- Compile-time error if constraint not met
Full Transcript
This example shows how to use generic constraints with extends in TypeScript. We define an interface HasName requiring a 'name' string property. Then we create a generic function greet that only accepts types extending HasName. When we call greet with an object having 'name' and 'age', it works because the object meets the constraint. The execution table traces each step: defining interface, function, creating object, calling function, checking constraint, returning greeting, and printing output. Key moments clarify why extra properties are allowed and what happens if the constraint is not met. The visual quiz tests understanding of output, constraint checking step, and error behavior. The snapshot summarizes the main points about generic constraints with extends.

Practice

(1/5)
1.

What does the extends keyword do in a TypeScript generic constraint?

easy
A. It limits the generic type to types that match a specific shape or interface.
B. It makes the generic type optional.
C. It allows the generic type to be any type without restriction.
D. It converts the generic type to a string.

Solution

  1. Step 1: Understand the role of extends in generics

    The extends keyword in generics restricts the generic type to only those types that satisfy a certain condition, usually matching an interface or type shape.
  2. Step 2: Compare with other options

    Options B, C, and D describe behaviors unrelated to extends in generics. It does not make types optional, allow any type, or convert types to strings.
  3. Final Answer:

    It limits the generic type to types that match a specific shape or interface. -> Option A
  4. Quick Check:

    Generic constraints = limit type shape [OK]
Hint: Remember: extends restricts generic types to certain shapes [OK]
Common Mistakes:
  • Thinking extends makes a type optional
  • Confusing extends with type conversion
  • Assuming extends removes restrictions
2.

Which of the following is the correct syntax to constrain a generic type T to an object with a name property of type string?

function greet<T>(obj: T): string {
return `Hello, ${obj.name}`;
}
easy
A. function greet<T>(obj: T extends { name: string }): string
B. function greet<T extends { name: string }>(obj: T): string
C. function greet<T = { name: string }>(obj: T): string
D. function greet<T>(obj: T & { name: string }): string

Solution

  1. Step 1: Identify correct generic constraint syntax

    The correct way to constrain a generic type is using T extends { name: string } inside the angle brackets.
  2. Step 2: Check other options for syntax errors

    function greet<T = { name: string }>(obj: T): string uses assignment (=) which is for default types, not constraints. function greet<T>(obj: T extends { name: string }): string misplaces extends outside the angle brackets. function greet<T>(obj: T & { name: string }): string uses intersection (&) in parameter type, which is valid but not a generic constraint.
  3. Final Answer:

    function greet<T extends { name: string }>(obj: T): string -> Option B
  4. Quick Check:

    Use extends inside <> for constraints [OK]
Hint: Use extends inside <> for constraints [OK]
Common Mistakes:
  • Using = instead of extends for constraints
  • Placing extends outside generic brackets
  • Confusing intersection types with constraints
3.

What will be the output of this TypeScript code?

interface HasId { id: number; }
function getId<T extends HasId>(obj: T): number {
return obj.id;
}
const item = { id: 42, name: 'Book' };
console.log(getId(item));
medium
A. Error: Type argument does not satisfy constraint
B. undefined
C. Error: Property 'id' does not exist
D. 42

Solution

  1. Step 1: Check if item satisfies the constraint

    The interface HasId requires an id property of type number. The object item has id: 42, so it satisfies T extends HasId.
  2. Step 2: Understand function behavior

    The function returns obj.id, so calling getId(item) returns 42.
  3. Final Answer:

    42 -> Option D
  4. Quick Check:

    Object matches constraint, returns id [OK]
Hint: Check if argument matches constraint to predict output [OK]
Common Mistakes:
  • Assuming runtime error due to missing explicit type
  • Confusing property existence with type errors
  • Thinking generic constraints affect runtime output
4.

Identify the error in this TypeScript code and select the fix:

function printLength<T>(arg: T): number {
return arg.length;
}
medium
A. Add constraint: <T extends { length: number }>
B. Change return type to void
C. Remove length property access
D. Use any instead of generic T

Solution

  1. Step 1: Identify cause of error

    The generic type T has no guarantee to have a length property, so accessing arg.length causes a compile error.
  2. Step 2: Fix by adding a constraint

    Adding T extends { length: number } ensures arg has a length property, fixing the error.
  3. Final Answer:

    Add constraint: <T extends { length: number }> -> Option A
  4. Quick Check:

    Constraint ensures property exists [OK]
Hint: Add extends constraint to guarantee properties exist [OK]
Common Mistakes:
  • Ignoring missing property errors
  • Changing return type instead of fixing constraint
  • Using any defeats generic safety
5.

Given this interface and function, which call is valid and why?

interface Person {
name: string;
age: number;
}

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}

const person: Person = { name: 'Alice', age: 30 };

Which call is valid?

hard
A. getProperty(person, 0)
B. getProperty(person, 'height')
C. getProperty(person, 'name')
D. getProperty(person, 'toString')

Solution

  1. Step 1: Understand the generic constraints

    The function uses K extends keyof T, so the key must be a valid property name of T. For Person, valid keys are 'name' and 'age'.
  2. Step 2: Evaluate each option

    getProperty(person, 'name') uses 'name', which is a valid key. getProperty(person, 'height') uses 'height', not in Person. getProperty(person, 0) uses 0, not a key. getProperty(person, 'toString') uses 'toString', which is a method on Object prototype, not a key of Person interface.
  3. Final Answer:

    getProperty(person, 'name') -> Option C
  4. Quick Check:

    Key must be keyof object type [OK]
Hint: Use keys from interface only with keyof constraint [OK]
Common Mistakes:
  • Using keys not declared in interface
  • Passing numbers instead of string keys
  • Confusing prototype methods with interface keys
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard