Generics in TypeScript allow you to write versatile and type-safe code by abstracting over types. They are essential for creating reusable components that can adapt to different data types while maintaining the benefits of static type checking. By leveraging generics, you can enhance the robustness and flexibility of your TypeScript projects.
Generics in TypeScript provide a way to create reusable components that can work with different types while maintaining type safety. They allow you to define functions, classes and interfaces that can work with a variety of data types without sacrificing type checking at compile-time. Generics enable you to write more flexible and robust code by abstracting over the specific types that a component interacts with.
however, this approach has a drawback - it loses type information. If you call getFirstElement with an array of numbers, for example, you might expect TypeScript to infer that the return type is a number, but it won't. This is where generics come in to address this issue.
Imagine you're building a function that takes an array and returns the first element of that array. The straightforward way might look like this:
function getFirstElement(arr: any[ ]): any{ return arr[0]; }
Generics can also be apliied to casses. For instance, consider simple Container class that holds a single value:
class Container <T> { value: T; constructor(initialValue: T){ this.value =initialValue; } } const numberContainer = new container(42); //Type of numberContainer.value is interred as number const stringContainer = new container("hello") //Type of stringContainer.value is interred as string
Let's rewrite the getFirstElement function using generics:
function getFirstElement<T>(arr: T[ ]): T { return arr[0]; }
In this example, T is a type parameter that represents a placeholder for the actual type that will be provided when the function is called. When you call getFirstElement with an array of a specific type, TypeScript will infer the type T based on the provided array type, and the return type will be the same as the array's element type. This maintains type safety:
const numbers= [1,2,3]; const firstNumber= getFirstElement(numbers); // Type of firstNumber is interred as number
const strings = ["a","b","c"]; const fristString= getFristElement(strings); // Type of firstString is interred as string
Sometimes you may want to add constraints to your generics to limit the types they can work with. For instance, you might want to ensure that the generic type has a specific property:
interface lengthy{ length: number; } function getlength<T extends lengthy>( input: T) number{ return input.length; } const arrylength= getlength([1,2,3]); //Works. because arrays 'length' property const stringlength= getlength("hello"); //Works. because string 'length' property const numberlength= getlength(42); //Error. because numbers don't have a 'length' property