Generics in TypeScript provide a way to create flexible and reusable code components that can work with a variety of data types, reducing code redundancy. They are particularly useful when you want to create a component that can handle different types of data.
Use Cases:
- Generic Functions:
// A generic function named 'genericFn' that can work with any type 'T'.
function genericFn<T>(arg: T): T {
return arg;
}
let output1 = genericFn<string>("myString"); // type of output will be 'string'
let output2 = genericFn<number>(100); // type of output will be 'number'
Use Case: Generic functions are useful when you want to apply the same logic to different data types. In the example above, genericFn
can accept any type of argument and return a value of the same type.
- Generic Interfaces:
// A generic interface that describes a function.
interface UsefulFunction<T> {
(input: T): T;
}
// The 'usefulFn' function implements the 'UsefulFunction' interface.
let myUsefulFunction: UsefulFunction<number> = usefulFn;
Use Case: Generic interfaces can be used to define a contract for classes or functions that can work with different data types. In the example above, UsefulFunction
describes a function that takes an input of type T
and returns a value of the same type.
- Generic Classes:
// A generic class 'GenericNumber' that works with a set of types.
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; };
Use Case: Generic classes are useful when you want to create a class that can work with different data types. In the example above, GenericNumber
can work with any numeric type.
- Generic Constraints:
// A generic function 'getProperty' with a constraint that 'T' must have a property 'K'.
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
let x = { a: 1, b: 2, c: 3, d: 4 };
getProperty(x, "a"); // okay
getProperty(x, "m"); // error: Argument of type 'm' isn't assignable to 'a' | 'b' | 'c' | 'd'.
Use Case: Generic constraints allow you to limit the types that can be used with a generic function, class, or interface. In the example above, getProperty
can only be used with objects that have a property of type K
.
Pros of Generics:
- Code reusability: Generics allow you to write a piece of code once and reuse it with different data types.
- Type safety: Generics provide compile-time type checking, reducing runtime errors.
Cons of Generics:
- Complexity: Generics can make the code more complex and harder to understand for beginners.
- Debugging: Debugging generic code can be challenging because the actual type is not known until runtime.