Understanding keyof and extends in Generics — Typescript

4 min readOct 21, 2024

Disclaimer: This is my personal blog. The opinions expressed in this blogpost are my own & do not necessarily represent the opinions, beliefs or viewpoints of my current or any previous employers.

I have recently started looking into TypeScript. One of the concepts that puzzled me was the use of generics, particularly the keyof and extends keywords.

In this article, I'll break down these concepts, explain their differences, and illustrate how they can work together to create more robust and flexible code.

What Are Generics?

Generics in TypeScript allow you to create reusable components that can work with any data type. This is especially useful for functions, classes, and interfaces. Generics enable you to define a placeholder type that can be specified later, allowing for more type-safe code.

The keyof Operator

The keyof operator enables you to obtain the keys of an object type as a union of string literal types. This means you can create types that are constrained to the keys of an object, ensuring type safety when accessing properties.

Example of keyof

Let’s consider a simple interface:

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

Using keyof, we can create a type that represents the keys of the Person interface:

type PersonKeys = keyof Person; // "name" | "age"

This is particularly useful when you want to write a function that accesses properties dynamically:

function getValue<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
// Example usage:
const person: Person = { name: "Alice", age: 30 };
const name = getValue(person, "name"); // Type is string
const age = getValue(person, "age"); // Type is number

In this example, getValue ensures that the key parameter is a valid key of the obj, preventing potential runtime errors.

The extends Keyword

On the other hand, the extends keyword is used in generics to restrict the type that can be passed. This allows you to enforce certain structures or properties on the generic type.

Example of extends

The extends keyword in TypeScript serves multiple purposes, primarily in generics. It allows you to constrain the types that can be passed into a generic function, class, or interface. This means you can specify that a type must satisfy certain conditions or implement certain properties.

Use Cases for extends

  1. Constraining Generic Types: This is the most common use of extends. It ensures that the type passed as a generic argument adheres to a specific structure or interface.
  2. Conditional Types: extends can also be used in conditional types to create type mappings based on whether a type extends another type.

1. Constraining Generic Types

When defining a generic function or class, you can use extends to restrict the types that can be used. Here's an example:

interface Animal {
name: string;
}

interface Dog extends Animal {
bark: () => void;
}
function makeSound<T extends Animal>(animal: T): void {
console.log(`This animal is named ${animal.name}`);
}
// Example usage:
const dog: Dog = {
name: "Buddy",
bark: () => console.log("Woof!"),
};
makeSound(dog); // Valid
// makeSound({ bark: () => {}, age: 5 }); // Error: Object is not assignable to parameter of type 'Animal'.

In this example, the makeSound function only accepts types that extend the Animal interface. This ensures that any object passed in will have at least a name property.

2. Conditional Types

The extends keyword can also be utilized in conditional types to create more complex type logic. This allows you to define types based on whether a certain condition is met.

Here’s an example:

type IsString<T> = T extends string ? "Yes" : "No";

// Example usage:
type Test1 = IsString<string>; // "Yes"
type Test2 = IsString<number>; // "No"
type Test3 = IsString<"Hello">; // "Yes"

In this case, the IsString type checks if the given type T extends string. If it does, it resolves to "Yes"; otherwise, it resolves to "No".

Combining keyof and extends

You can also combine both keyof and extends to create even more powerful and type-safe functions.

Imagine you have an object representing a user profile, and you want to create a function that updates a specific property of this object. Using keyof and extends, you can ensure that the function only accepts valid keys of the object.

Step 1: Define the User Profile Interface

First, let’s define a simple interface for a user profile:

interface UserProfile {
name: string;
age: number;
email: string;
}

Now, we’ll create a function that allows updating a property of the UserProfile. This function will use both keyof and extends to ensure type safety:

function updateProfile<T extends UserProfile, K extends keyof T>(profile: T, key: K, value: T[K]): T {
return { ...profile, [key]: value };
}

Explanation

  • <T extends UserProfile>: This means T can be any type that extends UserProfile. This gives flexibility if you want to have additional properties in the user profile.
  • <K extends keyof T>: This ensures that K is a valid key of T. This means you can only pass a key that exists on the profile object.
  • value: T[K]: This specifies that the value must be of the same type as the property being updated.

Let’s see how this function works in practice:

const user: UserProfile = {
name: "Alice",
age: 30,
email: "alice@example.com",
};
// Updating the users age

const updatedUser = updateProfile(user, "age", 31);
console.log(updatedUser); // { name: "Alice", age: 31, email: "alice@example.com" }

// Updating the user's email
const updatedEmailUser = updateProfile(user, "email", "alice.new@example.com");
console.log(updatedEmailUser); // { name: "Alice", age: 30, email: "alice.new@example.com" }


// The following line would produce a TypeScript error, as "address" is not a key of UserProfile:
// const errorUser = updateProfile(user, "address", "123 Main St");

Feel free to share your thoughts or experiences with TypeScript in the comments below. Happy coding!

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Namrata
Namrata

Written by Namrata

Engineering @Microsoft A software developer writing her daily bits . https://www.linkedin.com/in/namrataagarwal5/

No responses yet

Write a response