How to get better at Typescript Generics

Generics are hard!

Or at least, many of us seem to think that way. It is a viewpoint I have seen shared many times over, partially implying that “Generics” is a concept, much more difficult than most other Typescript concepts.

I’m here to tell you, it’s not!

It’s easy for that all-too-common imposter syndrome to kick in, once we get started with something that was supposed to just be a quick detour to verify our skills – perhaps a simple project, or even something as simple as Type Challenges – but turns out to be extremely difficult.

This is true, even for individuals who have been programming for many years! We can end up finding ourselves discouraged, leading to the question:

How do I get better at Generics?

It simply seems too difficult to grasp. So how do we learn it?

Generics are simply abstract type definitions

Well that sounds easy enough!

… Or does it? Let’s take a look with an example.

We might define a simple type something like this:

Defining the abstract type Generic MyType

This is simply telling the Typescript compiler the following:

  • I take a type A as the first parameter
  • I take a type B as the second parameter
  • I return an object with two values:
    • Value a, which is of the (expected) type A
    • Value b, which is of the (expected) type OtherType*
      • OtherType has an input parameter, which takes input in the same format as type B.

Before we dive into what each of those lines mean, let’s take a look at how this might look in plain javascript:

Abstract type generic MyType written out in plain Javascript

Here it hopefully becomes a little more clear, what the intention behind the method is.

My estimate is that the part that confuses a lot of programmers when writing types in Typescript, is the OtherType<B> in this example.

But that’s all there is to it!

Remember if you ever come across the <A, B> pattern in Typescript, or a variation using any letters or words, they are just placeholders for things that are common in Javascript.

The use-case for Generics is typically when you have a shared interface that you may want to re-use across multiple slightly different things. Key here being slightly.

An excellent example may be an interface for an API, where the response is always the same format but the contents are different.
I’ve personally used this little snippet many times:

Typescript abstract type definition for API results

I hope this little explainer helped solve some of the confusion around how Generics are defined in Typescript.

Also, feel free to re-use my snippet 😉

type TResults<T = null> = {
	success: boolean;
	message?: string;
	data: T;
	pagination?: IPagination;