The Magic of Generic Interfaces in TypeScript π
Okay then, so now you're getting the hang of how generic functions work in TypeScript, right? But hold onto your hats, because it's not just functions that can be genericβyou can also make generic type aliases, generic classes, and (drum roll, please) generic interfaces! π₯³ In this lesson, we're going to take a quick look at generic interfaces.
Generic interfaces work much the same way as generic functions. You can capture a type when you use the interface and then use that captured type to assign types to different parts of the interface. Ready to dive in? Letβs go! π
Example: Creating a Generic Interface
Let's start with a simple example. Imagine we have an interface called Collection
that describes an object with two properties: data
and name
.
typescriptCopy code
interface Collection {
data: string[];
name: string;
}
// Usage
const stringCollection: Collection = {
data: ["Mario", "Luigi", "Peach"],
name: "Mario Characters"
};
So far, so good. This works well for a collection where the data
property is a string array. But what if we want a collection of numbers, dates, or custom objects like user objects? π€
Making the Interface Generic
To handle different data types, we can make the interface generic by adding angle brackets after the interface name and a type parameter (usually T
).
typescriptCopy code
interface Collection<T> {
data: T[];
name: string;
}
// Usage with different types
const stringCollection: Collection<string> = {
data: ["Mario", "Luigi", "Peach"],
name: "Mario Characters"
};
const numberCollection: Collection<number> = {
data: [10, 15, 27, 9, 3, 34],
name: "Winning Lottery Numbers (I wish!)"
};
Practical Example with Generic Interfaces
Let's see a more detailed example. Suppose we have a function that picks a random item from a collection.
typescriptCopy code
interface Collection<T> {
data: T[];
name: string;
}
function getRandomItem<T>(collection: Collection<T>): T {
const randomIndex = Math.floor(Math.random() * collection.data.length);
return collection.data[randomIndex];
}
// Using the function with different types
const stringCollection: Collection<string> = {
data: ["Mario", "Luigi", "Peach"],
name: "Mario Characters"
};
const numberCollection: Collection<number> = {
data: [10, 15, 27, 9, 3, 34],
name: "Winning Lottery Numbers (I wish!)"
};
console.log(getRandomItem(stringCollection)); // Output: Random Mario character
console.log(getRandomItem(numberCollection)); // Output: Random lottery number
A More Advanced Example: Constraining Generic Types
Sometimes, you might want to limit the types that can be used with your generic interface. For instance, you might want to ensure that the items in your collection have certain properties.
typescriptCopy code
interface Identifiable {
id: number;
}
interface Collection<T extends Identifiable> {
data: T[];
name: string;
}
function getItemById<T extends Identifiable>(collection: Collection<T>, id: number): T | undefined {
return collection.data.find(item => item.id === id);
}
// Usage with constrained types
const userCollection: Collection<{ id: number; name: string }> = {
data: [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" }
],
name: "User Collection"
};
console.log(getItemById(userCollection, 1)); // Output: { id: 1, name: "Alice" }
Wrapping Up
And there you have it! π With generic interfaces, you can create more flexible and type-safe code in TypeScript. By understanding how to use generics, you can make your code adaptable to different data types while maintaining strong type safety. Remember, TypeScript's power lies in its ability to provide both flexibility and security. So go ahead, experiment with generics, and make your TypeScript code even more awesome! π
Top comments (0)