How to make Generic Functions that change return value type according to the parameter values type in TypeScript?

To make a general function that changes the return value type according to the parameter type value, we can make use of a concept called Generic functions (aka General Functions) in TypeScript.

The basic idea of generic functions is to have a type safety by associating the type of the function parameters types (input) with the return value type (output) of the function.

In simple terms, Generic functions are those functions that set their type dynamically without us specifying it manually.

TL;DR

// Logic of the function is to get the first element from the array
// The Function is also a Generic Function
// and type safe where it can accept an array
// of any type and returns the same type
// of first element dynamically without
// we defining the type manually
function getFirstElement<GeneralType>(arr: GeneralType[]): GeneralType {
  return arr[0];
}

// call the function with array of numbers
const value1 = getFirstElement([1, 2, 3, 4]); // type => number ๐Ÿ˜

// call the function with array of strings
const value2 = getFirstElement(["hello", "hai", "hey"]); // type => string ๐Ÿ˜

To understand it more clearly, let's consider a function that returns the first element from the array.

It may look like this,

// Logic of the function is to get the first element from the array
function getFirstElement(arr) {
  return arr[0];
}

Now let's call the getFirstElement function and pass a array of numbers like this,

// Logic of the function is to get the first element from the array
function getFirstElement(arr) {
  return arr[0];
}

// call the function
const value1 = getFirstElement([1, 2, 3, 4]); // type => any ๐Ÿ˜•

Now if we were to analyze the type of the value1 variable, we can see that the type is of any which is the expected behavior of the function since we haven't defined the parameter type as well as the return value type.

So to avoid this problem, let's define the parameter types and also types for the return value.

Let's make the parameter arr to hold an array of numbers and the return value of the function be a number.

It can be done like this,

// Logic of the function is to get the first element from the array
function getFirstElement(arr: number[]): number {
  return arr[0];
}

// call the function
const value1 = getFirstElement([1, 2, 3, 4]); // type => number ๐Ÿ™‚

Now if we look into the return type of the getFirstElement function call we can see that the type is of number which is good.

Now another problem arises where we also need to get the first value if the array contains elements that are of string type which we cannot do with our current function even though the mechanism or the logic we need is of the same.

In this case, we need to make the function into a general function where we need to associate the type of the parameter (input) with that of the return value type (output).

Let's make the getFirstElement function into a generic function by using a Type Parameter.

A Type parameter is declared by writing out the general type name inside an angled bracket symbol (<>) after the function name.

Let's name our Type parameter as GeneralType.

It can be done like this,

// Logic of the function is to get the first element from the array
function getFirstElement<GeneralType>(arr: number[]): number {
  return arr[0];
}

// call the function
const value1 = getFirstElement([1, 2, 3, 4]); // type => number ๐Ÿ™‚

Now that we have declared a general Type parameter.

We need to tell the function to accept an array of any value type and it should also return the correct type of the first element in the array.

So let's use the Type parameter called GeneralType wherever we have used the number type.

It can be done like this,

// Logic of the function is to get the first element from the array
// The Function is also a Generic Function
// and type safe where it can accept an array
// of any type and returns the same type
// of first element dynamically without
// we define the type manually
function getFirstElement<GeneralType>(arr: GeneralType[]): GeneralType {
  return arr[0];
}

// call the function
const value1 = getFirstElement([1, 2, 3, 4]); // type => number ๐Ÿ™‚

The getFirstElement function is now a Generic Function and can now accept an array of any value type and returns the same type of the first element from the array dynamically.

Now let's try to call the getFirstElement with both array of numbers and array of strings and analyze the return types.

It can be done like this,

// Logic of the function is to get the first element from the array
// The Function is also a Generic Function
// and type safe where it can accept an array
// of any type and returns the same type
// of first element dynamically without
// we define the type manually
function getFirstElement<GeneralType>(arr: GeneralType[]): GeneralType {
  return arr[0];
}

// call the function with array of numbers
const value1 = getFirstElement([1, 2, 3, 4]); // type => number ๐Ÿ˜

// call the function with array of strings
const value2 = getFirstElement(["hello", "hai", "hey"]); // type => string ๐Ÿ˜

As you can see that the return type of the value1 and the value2 variables is according to the type of the array elements passed to the getFirstElement function.

Yay ๐Ÿฅณ! We have made our function into a Generic Function.

See the above code live in codesandbox.

That's all ๐Ÿ˜ƒ!

Feel free to share if you found this useful ๐Ÿ˜ƒ.

24