Generics provide a way to create reusable components in TypeScript. They allow you to define a component that can work with a variety of data types rather than a single one. This makes your code more flexible and reusable.
Key Concepts
- Generic Functions: Functions that can operate on any data type.
- Generic Classes: Classes that can handle multiple data types.
- Generic Interfaces: Interfaces that can be used with different data types.
- Constraints: Restrictions on the types that can be used with generics.
Generic Functions
A generic function can work with any data type. Here's a simple example:
T
is a type variable that acts as a placeholder for the type that will be passed to the function.- When you call
identity
, you can specify the type explicitly or let TypeScript infer it.
Example
let output1 = identity<string>("Hello, TypeScript!"); // Explicit type let output2 = identity(42); // TypeScript infers the type as number
Generic Classes
Generic classes can create objects that work with multiple data types. Here's an example:
class GenericNumber<T> { zeroValue: T; add: (x: T, y: T) => T; } let myGenericNumber = new GenericNumber<number>(); myGenericNumber.zeroValue = 0; myGenericNumber.add = function(x, y) { return x + y; };
T
is a type variable that allows the class to work with any data type.- You can create instances of
GenericNumber
with different types.
Generic Interfaces
Generic interfaces can define the shape of objects that can work with multiple data types. Here's an example:
interface GenericIdentityFn<T> { (arg: T): T; } function identity<T>(arg: T): T { return arg; } let myIdentity: GenericIdentityFn<number> = identity;
T
is a type variable that allows the interface to work with any data type.- You can create instances of
GenericIdentityFn
with different types.
Constraints
Sometimes you want to restrict the types that can be used with generics. You can achieve this using constraints. Here's an example:
interface Lengthwise { length: number; } function loggingIdentity<T extends Lengthwise>(arg: T): T { console.log(arg.length); // Now we know it has a .length property, so no error return arg; } loggingIdentity({ length: 10, value: 3 });
T extends Lengthwise
means thatT
must have alength
property.- This allows you to use generics with more specific types.
Practical Exercise
Exercise
Create a generic function merge
that takes two objects and merges them into one. The function should return the merged object.
function merge<T, U>(obj1: T, obj2: U): T & U { return { ...obj1, ...obj2 }; } // Test the function const obj1 = { name: "John" }; const obj2 = { age: 30 }; const mergedObj = merge(obj1, obj2); console.log(mergedObj); // Output: { name: "John", age: 30 }
Solution
function merge<T, U>(obj1: T, obj2: U): T & U { return { ...obj1, ...obj2 }; } // Test the function const obj1 = { name: "John" }; const obj2 = { age: 30 }; const mergedObj = merge(obj1, obj2); console.log(mergedObj); // Output: { name: "John", age: 30 }
Common Mistakes and Tips
- Forgetting to Specify the Type: If you don't specify the type, TypeScript will try to infer it. This can sometimes lead to unexpected results.
- Overusing Generics: While generics are powerful, overusing them can make your code harder to read and maintain. Use them judiciously.
- Ignoring Constraints: Constraints help ensure that your generics work with the types you expect. Use them to avoid runtime errors.
Conclusion
Generics are a powerful feature in TypeScript that allow you to create flexible and reusable components. By understanding how to use generic functions, classes, interfaces, and constraints, you can write more robust and maintainable code. In the next section, we will explore Type Aliases, which provide another way to define custom types in TypeScript.
TypeScript Course
Module 1: Introduction to TypeScript
- What is TypeScript?
- Setting Up the TypeScript Environment
- Basic Types
- Type Annotations
- Compiling TypeScript
Module 2: Working with Types
Module 3: Advanced Types
Module 4: Functions and Modules
Module 5: Asynchronous Programming
Module 6: Tooling and Best Practices
- Linting and Formatting
- Testing TypeScript Code
- TypeScript with Webpack
- TypeScript with React
- Best Practices