📖 Scenario: Imagine you are building a small program to handle different types of shapes. Each shape has a name and a method to calculate its area. You want to write a function that can accept any shape but only if it has these properties.
🎯 Goal: Build a TypeScript function using generics with extends to accept only objects that have a name string and an area method returning a number.
📋 What You'll Learn
Create an interface called Shape with a name property of type string and an area method returning number.
Create a generic function called printShapeInfo that accepts a parameter T constrained to Shape using extends.
Inside the function, print the shape's name and the result of calling its area method.
Create an object circle with name as 'Circle' and an area method returning 3.14 * radius * radius where radius is 5.
Call printShapeInfo with the circle object.
💡 Why This Matters
🌍 Real World
Using generic constraints helps ensure functions only accept objects with the right shape, preventing errors and making code easier to understand.
💼 Career
Many programming jobs require writing reusable and safe code. Understanding generics with constraints is key for working with TypeScript and other typed languages.
Progress0 / 4 steps
1
Create the Shape interface
Create an interface called Shape with a name property of type string and an area method that returns a number.
Typescript
Hint
Use the interface keyword to define the shape of an object.
2
Create the generic function with extends constraint
Create a generic function called printShapeInfo with a type parameter T that extends Shape. The function should accept a parameter shape of type T.
Typescript
Hint
Use to restrict the generic type.
3
Print the shape's name and area inside the function
Inside the printShapeInfo function, write two console.log statements: one to print shape.name and another to print the result of shape.area().
Typescript
Hint
Use template strings with console.log to show the values.
4
Create a circle object and call the function
Create a constant circle with name set to 'Circle' and an area method that returns 3.14 * 5 * 5. Then call printShapeInfo(circle).
Typescript
Hint
Define circle as an object literal with the required properties and call the function.
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
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.
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.
Final Answer:
It limits the generic type to types that match a specific shape or interface. -> Option A
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
The correct way to constrain a generic type is using T extends { name: string } inside the angle brackets.
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.
Final Answer:
function greet<T extends { name: string }>(obj: T): string -> Option B
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
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.
Step 2: Fix by adding a constraint
Adding T extends { length: number } ensures arg has a length property, fixing the error.
Final Answer:
Add constraint: <T extends { length: number }> -> Option A
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
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'.
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.
Final Answer:
getProperty(person, 'name') -> Option C
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 unknownstrongwhile earning +1 Grip toward your certificate.