Skip to content

Generics

von Schappler edited this page Nov 27, 2024 · 1 revision

What are Generics?

Generics in TypeScript is a tool that allows us to add flexibility to your existing functions, types and everything else in our code. We can think of it like as function parameters, which hold types instead of values. Generics are declared in the code with a pair of opening and closing angle brackets as already discussed before in previous lectures.

To understand what generics are, let take, for example, the case of "array like" variables. We know that arrays can store any type of variables (number, strings, objects, booleans, etc.) - our problem here is how we should make the correct type declaration of a "generic" array passed for example as an argument to a funcion and how to specify the return type of that function?

To understand this, let's assume the snippet of code below, where we have some array like variables, with different types and we want to get the last element of this array:

type Person = {
  name: string;
  age: number;
};
const arr1 = [1, true, () => console.log('hello')];
const arr2 = [{ name: 'Bob', age: 10 }, 'Love cats'];
const bool: boolean[] = [true, false, true];
const obj: Person[] = [
  { name: 'Bob', age: 10 },
  { name: 'Anna', age: 12 },
];
const str: string[] = ['peace', 'potato', 'banana', 'dogs'];
const nbrs: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const getLast = (arr) => arr.at(-1);

console.log(getLast(arr1));
console.log(getLast(arr2));
console.log(getLast(bool));
console.log(getLast(obj));
console.log(getLast(str));
console.log(getLast(nbrs));

In this function (getLast()) we have basically some problems we need to solve:

  1. We currently implicity declaring the type of our argument arr as any.
  2. Even if we explicitly declare that as any, this is recommended
  3. We have arrays where their elements are of different types or multiple types of array which can be passed as arguments, which then "forbid us" of specify a single type for the array, as we are used to do, eg. getLast(arr: string[]).

The common ground that helps us to solve this problem is then the use of Generics.


Using Generics:

1. With named functions

The snippet of code below exemplifies how generics are used when we are writing named functions:

function getLastItem<Type>(arr: Type[]) {
  return arr.at(-1);
}

2. With arrow functions

const getLastItemEs6 = <Type>(arr: Type[]) => {
  return arr.at(-1);
};

Note

  1. The word Type used between the angle brackets AND for the type definition of the argument of the function is usually seen as T. This can be anything as long as we keep consistent with the type name / code style, eg.:
const a = <T>(arg: T[]) => {
  /*function code */
};

const b = <ArgType>(arg: ArgType[]) => {
  /*function code */
};
  1. The return type for generics should also be declared in a explicity way and that is a union of both the Generic type created AND undefined:
const a = <T>(arg: T[]): T | undefined => {
  /*function code */
};
Clone this wiki locally