Generics
Creating reusable, type-safe components
Introduction
In this lesson, you'll learn about generics in TypeScript. Coming from JavaScript, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.
In JavaScript, you're familiar with creating reusable, type-safe components.
TypeScript has its own approach to creating reusable, type-safe components, which we'll explore step by step.
The TypeScript Way
Let's see how TypeScript handles this concept. Here's a typical example:
// TypeScript generics preserve type information
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
function identity<T>(value: T): T {
return value;
}
// Types are preserved
const num = first([1, 2, 3]); // number | undefined
const str = identity("hello"); // stringComparing to JavaScript
Here's how you might have written similar code in JavaScript:
// JavaScript - no way to maintain type relationships
function first(arr) {
return arr[0];
}
function identity(value) {
return value;
}
// Type is lost
const num = first([1, 2, 3]); // any
const str = identity("hello"); // anyYou may be used to different syntax or behavior.
Generics use <T> to create type parameters
You may be used to different syntax or behavior.
Type is captured when function is called
You may be used to different syntax or behavior.
Enables type-safe reusable components
Step-by-Step Breakdown
1. Generic Functions
Generics let you write functions that work with any type while maintaining type safety.
function wrap<T>(value: T): { value: T } {
return { value };
}
const wrapped = wrap(42); // { value: number }
const wrappedStr = wrap("hi"); // { value: string }2. Generic Interfaces
Interfaces can also be generic.
interface Box<T> {
value: T;
getValue(): T;
}
const numBox: Box<number> = {
value: 42,
getValue() { return this.value; }
};3. Generic Constraints
Use extends to constrain what types a generic can accept.
interface HasLength {
length: number;
}
function logLength<T extends HasLength>(item: T): void {
console.log(item.length);
}
logLength("hello"); // OK - strings have length
logLength([1, 2, 3]); // OK - arrays have length
// logLength(123); // Error - numbers don't have lengthCommon Mistakes
When coming from JavaScript, developers often make these mistakes:
- Generics use <T> to create type parameters
- Type is captured when function is called
- Enables type-safe reusable components
Key Takeaways
- Generics create type parameters with <T>
- They preserve type information through operations
- Constraints limit what types generics accept
- Common generic names: T (Type), K (Key), V (Value)