...

/

Generic Functions

Generic Functions

This lesson introduces generic functions.

Motivation #

Let’s say you are adding types to some JavaScript codebase and you encounter this function:

Press + to interact
function getNames(persons) {
const results = [];
for (let person of persons) {
results.push(person.name);
}
return results;
}
console.log(getNames([
{ name: 'John' },
{ name: 'Alice' },
]));

Typing this function is straightforward. It accepts an array of person objects as a parameter and returns an array of names (strings). For the person object, you can either create a Person interface or use one that you’ve already created.


interface Person {
  name: string;
  age: number;
}

function getNames(persons: Person[]): string[] {
  /* ... */
}

Next, you notice that you don’t actually need this function. Instead, you can use the built-in Array.map method.

Press + to interact
interface Person { name: string; }
const persons: Person[] = [
/* ... */
];
const names = persons.map(person => person.name);

Hmm, but what about types? You check the type of names and realize that it has been correctly inferred to string[]! How does TypeScript achieve this?

To properly understand this, let’s try to type the following implementation of map function.

Press + to interact
function map(items, mappingFunction) {
const results = [];
for (let item of items) {
results.push(mappingFunction(item));
}
return results;
}
const persons = [
{ name: 'John' },
{ name: 'Alice' },
];
console.log(map(persons, person => person.name));

The main issue with typing map is that you don’t know anything about the type of the elements of the array it will be called with. What makes map so cool is that it works with any kind of array!

// Works with array of Persons
const names = map(persons, person => person.name);
// Works with array of names too
const uppercaseNames = map(names, name => name.toUpperCase());
// Works even with an array of numbers!
const evenNumbers = map([1, 2, 3, 4, 5], n => n * 2);

Let’s use

...