Table of Contents
Issue
When writing a function in TypeScript, is there a way to let the function infer what to do according to the input’s type?
For example, let’s say that I have a function that calculates the maximum value.
-
In scenario A, the input is a numeric array (i.e.,
type: number[]
), and I want it to return the max value. So I could do:const calcMaxArr = (arr: number[]): number => { return Math.max(...arr) // https://stackoverflow.com/a/39106546/6105259 }
-
In scenario B I also want to calculate the max value, but this time my input data is an object, and I want to return the key that corresponds to the largest value. In this case I could do:
const calcMaxObj = (obj: Record<string, number>): string => { return Object.keys(obj).reduce((a, b) => obj[a] > obj[b] ? a : b); //https://stackoverflow.com/a/27376421/6105259 }
While these two functions (calcMaxArr()
& calcMaxObj()
) work perfectly well, I wonder whether I could unify them somehow under one function calcMax()
. That is, I wonder whether calcMax()
can infer, from the input’s type, whether to defer/dispatch the calculation to calcMaxArr()
or to calcMaxObj()
.
If type: number[] -> calcMaxArr()
If type: Record<string, number> -> calcMaxObj()
Is there a built-in feature in typescript for such kind of a task?
EDIT
I ran across this tweet that demonstrates a similar procedure but in python. For those who know python, this makes a useful analogy in my opinion.
EDIT 2
I’ve now learned that what I am asking about actually has a name: My calcMax()
is a generic function, and one built-in implementation of such generic functions is seen in Common Lisp, for example.
Solution
Does this work for you…
const calcMax = (inputs: number[] | Record<string, number>): number | string => {
if (Array.isArray(inputs)) {
return calcMaxArr(inputs);
}
return calcMaxObj(inputs);
}
const calcMaxArr = (arr: number[]): number => {
return Math.max(...arr) // https://stackoverflow.com/a/39106546/6105259
}
const calcMaxObj = (obj: Record<string, number>): string => {
return Object.keys(obj).reduce((a, b) => obj[a] > obj[b] ? a : b); //https://stackoverflow.com/a/27376421/6105259
}
Illustration
"use strict";
const calcMax = (inputs) => {
if (Array.isArray(inputs)) {
return calcMaxArr(inputs);
}
return calcMaxObj(inputs);
};
const calcMaxArr = (arr) => {
return Math.max(...arr); // https://stackoverflow.com/a/39106546/6105259
};
const calcMaxObj = (obj) => {
return Object.keys(obj).reduce((a, b) => obj[a] > obj[b] ? a : b); //https://stackoverflow.com/a/27376421/6105259
};
console.log(calcMax([10, 8, 12, 3]));
console.log(calcMax({
"10": 10,
"8": 8,
"12": 12,
"3": 3
}));
WYSIWYG
=> WHAT YOU SHOW IS WHAT YOU GET
Answered By – Nalin Ranjan
Answer Checked By – Katrina (BugsFixing Volunteer)