Skip to content
Nate
Stephens

Generics are type parameters.

They are a way of defining types that are expressed in terms of other types.

Often they're used as a mechanism of defining a relationship between the type of thing we pass to a function, and the type of thing returned from that function. But they aren't limited to only being used with functions.

Defining a type parameter

Type parameters can be thought of as "function arguments, but for types".

Just like how functions will return different values depending on the arguments you pass them, Generics will change their type depending on the type parameters you supply to them.

function listToDict<T>(
  list: T[],
  idGen: (arg: T) => string
): { [k: string]: T } {
  const dict: { [k: string]: T } = {};

  list.forEach((element) => {
    const dictKey = idGen(element);
    dict[dictKey] = element;
  });

  return dict;
}

NOTE: we get a different kind of dictionary returned out of listToDict depending on the type of the array we pass in.

The TypeParam, and its usage to provide an argument type

<T> to the right of listDict

  • means that the type of this function is now parameterized in terms of a type parameter T
  • which may change on a per-usage basis

list: T[] as a first argument

  • means we accept a list of T‘s.

idGen: (arg: T) => string

  • means this function better be setup to take as an input whatever type T is (whatever list is an array of) b/c that's the type that arg will be
  • we will get type-checking alignment between the list array and the idGen function
  • we will get the benefits of type-checking within the idGen function

Again... TypeScript will infer what T is, on a per-usage basis, depending on what kind of array we pass in.

If we use a string[], T will be string.

If we use a number[], T will be number.

Simpler example:

function wrapInArray<T>(arg: T): [T] {
  return [arg];
}
// function wrapInArray<T>(arg: T): [T]

In use:

wrapInArray(3);
// function wrapInArray<number>(arg: number): [number]

wrapInArray(new Date());
// function wrapInArray<Date>(arg: Date): [Date]

wrapInArray(new RegExp('/s/'));
// function wrapInArray<RegExp>(arg: RegExp): [RegExp]

Generics Best Practices

  • The point of Generics and Type Parameters is to relate multiple things.
  • Use each type parameter at least twice.

From the TypeScript Fundamentals, v3 course on FEM taught by Mike North.


Last Updated: