Introduction to Typescript Generics

Emmanuel Onyebueke
3 min readApr 28, 2023

--

By the end of this Article, you will learn about typescript generics, what they are, their use cases, and a few examples.

In some cases, the types we create can be reusable as other types in a different context, and we do not need to start duplicating for each use case, we can use a generic to avoid duplication. Generics are used to create reusable types, as parameters are to functions so are generics to types.

For example,

enum Subject = {
Maths = 'Maths',
English = 'English',
Deutsch = 'Deutsch'
}

type Book = {
subject: Subject,
author: string,
year: number
}

/**
this function is expected to receive math books only, both book can be
Maths, Deutsch or English
*/
function takeMathsBookOnly(book: Book) {

}

In the code snippet above, we have a type Book with a property subject of enum Subject that can be Maths, English, or Deutsch, and we also have a function takeMathsBookOnly that expects to receive math books only. However, books as we know can be of be of any subject.

We can write a type guard within the function or write some condition to determine the book subject is Maths, but all of this complex logic could be avoided by using generics, we can create a specific type for each subject by using generics.

enum Subject = {
Maths = 'Maths',
English = 'English',
Deutsch = 'Deutsch'
}

// Default parameter = Subject, meaning Book
type Book<T = Subject> = {
subject: T, // subject: Subject
author: string,
year: number
}
type MathBook = Book<Subject.Maths> 
/** subject can only be equal to 'Maths'
{
subject: Subject.Maths,
author: string,
year: number
}
**/

type EnglishBook = Book<Subject.English>
/** subject can only be equal to 'English'
{
subject: Subject.English,
author: string,
year: number
}
**/

type DeutschBook = Book<Subject.Deutsch>
/** subject can only be equal to 'Deutsch'
{
subject: Subject.Deutsch,
author: string,
year: number
}
**/

function takeMathsBookOnly(book: MathBook) {

}

From the snippet above, Book now accepts a generic type variable called T , T just like function parameters accept Subject as it default type, so Book type is the same as the previous functionality, however, the added advantage is that we can now reuse the Book type in different contexts, we can create MathBook type only by passing Subject.Maths as an argument to Book , so in the case T = Subject.Maths . We can create as many specific types as we want using generics.

Another Generic Use case

// generic map function
const map = <T, U>(items: T[], fn: (item: T) => U): U[] => {
const result: U[] = [];
for (let item of items) {
result.push(fn(item));
}
return result;
}

const doubleNumbers = map<number, number>([1, 2, 3, 4, 5], (item) => item * 2);
// [2, 4, 6, 8, 10]

const stringifyDoubleNumbers = map<number, string>([1, 2, 3, 4, 5], (item) => `${item * 2}`);
// ['2', '4', '6', '8', '10']

Let’s examine another generic use case, in the above snippet we have a generic map function with two generic type variable T and U , which accepts items that is an array of T , and a callback function fn which accepts an item of the type T and returns U , sometimes U could be the same as T like in the doubleNumbers , but that is not always the case, we might need to transform items to another type like in the stringifyDoubleNumbers which receives an array of number but returns an array of string .

To read more on generics, check out Typescript Generics. Thank you

--

--