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 (whateverlist
is an array of) b/c that's the type thatarg
will be - we will get type-checking alignment between the
list
array and theidGen
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 bestring
.If we use a
number[]
,T
will benumber
.
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↗.