How to Create TypeScript Generic Arrow Function

Posted December 19, 2023
How to Create TypeScript Generic Arrow Function

Did you know normal Typescript functions can be generically typed as arrow generics? Generics makes you write functions, classes, and interfaces that work with different types while maintaining Typescript type safety.

Arrow functions are a shorthand syntax for writing TypeScript functions. I will show you the right way to write your TypeScript generic arrow functions.

Related: Setup and Build a Vanilla TypeScript API with Node.js

The Most basic TypeScript generic arrow function

You create generics with arrow functions with a generic type parameter between angle brackets (< and >) right before the function’s argument list in TypeScript.

You get it, right? The arrow brackets are added (<>) right before the function’s parameters or class declaration. This way TypeScript will know you are using Generics.

Here, you are making the Arrow functions generic using type parameters. When calling the function (with generics), the syntax remains the same as a regular function declaration. The generic type is passed right before the function’s parameters.

Check this quick example illustrating a typescript generic arrow function:

// Generic Arrow Function
const echo = <T>(value: T): T => value;

// Usage
const resultString: string = echo('Hello, TypeScript');
const resultNumber: number = echo(42);
const resultArray: number[] = echo([1, 2, 3]);

console.log(resultString); // Output: Hello, TypeScript
console.log(resultNumber); // Output: 42
console.log(resultArray);  // Output: [1, 2, 3]

How to Create TypeScript Generic Arrow Function

Demystifying TypeScript Generic Arrow Function Syntax

If in this case, we have the following function:

function echo<T>(value: T): T {
  return value;
}

First, take the TypeScript Generic Arrow Function itself:

const echo = <T>(value: T): T => value;
  • <T> is our actual generic type parameter declaration. Your generic will let TypeScript know the function will work with a type T. But note T itself is not specified until the function is called.
  • (value: T) => T: is the arrow function syntax with a single parameter value of type T and it returns a value of the same type T.
  • We can expand the same arrow function with the return and braces as follows:
const echo = <T>(value: T): T => {
  return value;
};
  • The fact that the example is using type T, means you can change it. Let’s say maybe use type E. The same generic typescript arrow function works for you. The only thing you need is to make sure it is uniform with the return type, like
const testValues = <E>(arg: E): E => arg;

Calling TypeScript Generic Arrow Function with Type Inference

Note that when calling your typescript generic arrow function, we haven’t explicitly specified generic. TypeScript infers the types based on the types of the arguments passed to the echo function as follows:

// Type inference 
const resultString: string = echo('Hello, TypeScript');
const resultNumber: number = echo(42);
const resultArray: number[] = echo([1, 2, 3]);

TypeScript will infer the types for resultArray, resultString, and resultNumber based on the types of the arguments passed to our echo function.

For example, resultString is an inferred type of string. The function echo is called with the type parameter explicitly set to string. TypeScript infers that T is a string for this particular declaration.

A Practical Application of TypeScript Generic Arrow Function Featuring React JSX

If you are a TypeScript person, you definitely use TypeScript with JSX. How about we try this approach with React? You can create generic arrow functions within a .tsx TypeScript file. And it is just as you would in a regular TypeScript file. The application is the same:

  • You create a Generic Arrow function as a component and still with a type
  • You create Type inference add declarations and use the generic component.

Check this example of how simple the generic arrow function can be while still using .tsx:

import React from 'react';

//Create Generic arrow function
const EchoComponent = <T,>(props: { data: T }): JSX.Element => {
  return (
    <div>
      <p>{props.data}</p>
    </div>
  );
};

// using the generic component
const App: React.FC = () => {
  // add a type inference
  const stringComponent = <EchoComponent data="Hello, I'm a TypeScript Generic Arrow Function! Do You Like Me?" />;

  return (
    <div>
      {stringComponent}
    </div>
  );
};

export default App;

The key takeaway if you are using typescript arrow function generics in .txs is:

  • Type T has a trailing comma <T,>.
  • You write type-safe components with any data types.

The same applies where you are using a TypeScript Generic Higher-Order Component like this one:

You are not limited to where you can use TypeScript alongside Generic Arrow Function. Let’s explore a few examples here:

Higher-Order Function with Generic Arrow Function:

You didn’t know Higher-Order Functions can use Generics, right? Check this example:

const mapArray = <T, U>(arr: T[], mapper: (item: T) => U): U[] => {
    return arr.map(mapper);
};

const numbers = [1, 2, 3, 4, 5];
const squaredNumbers = mapArray(numbers, (num) => num * num);
console.log(squaredNumbers); // Output: [1, 4, 9, 16, 25]

mapArray is a higher-order function that is generic with type parameters T and U.

At the same you have a generic arrow function ((item: T) => U) taking type T and returning a value of type U.

Once you call arr.map(mapper), the function maps each item to the array as an output array of type U.

Using TypeScript Generic Arrow Function Class and Constraints:

Arrow functions are used within the class to define methods. The Following Container is a generic class with a constraint (extends number | string):

class Container<T extends number | string> {
    private value: T;

    constructor(initialValue: T) {
        this.value = initialValue;
    }

    getValue = (): T => {
        return this.value;
    };
}

// using the generic class
const numberContainer = new Container<number>(42);
console.log(numberContainer.getValue()); // Output: 42

const stringContainer = new Container<string>("Hello, Generic Class");
console.log(stringContainer.getValue()); // Output: Hello, Generic Class

Note that:

  • The arrow function syntax (= (): T =>) create getValue method.
  • The constraint restricts the allowable types to only numbers and strings.
  • This getValue method returns the private value property. Therefore, the class constructor initializes the value property with an initial value of type T that getValue returns.

How TypeScript Generic Arrow Function Looks with keyof

The keyof operator obtains the union type of all property names you have in a type. This way, you will refer to the set of keys of an object type and work with object property names as type-safe.

What if you have Generics and an arrow function? Here is your simple keyof:

const getProperty = <T, K extends keyof T>(obj: T, key: K): T[K] => {
    return obj[key];
};

//keyof with generics
const person = { name: "kIM", age: 30, city: "New York" };
//Valid
const personCity = getProperty(person, "city");
// Output: New York

Your arrow function takes an object (obj) and a key (key). Now TypeScript will ensure the key is a valid key of the object. You can verify that based on (K extends keyof T).

Check the return type is T[K]. Your function will only return the value type corresponding to the provided key with type safety.

For example, use:

const personAge: boolean = getProperty(person, 'age'); 
console.log(personCity);

How to Create TypeScript Generic Arrow Function

What if have a Default Value for Generic Type

If you are providing a default type, you add a default type parameter with (<T = string>) as follows.

const defaultValue = <T = string>(value?: T): T => {
  return (value || "Test TypeScript Generics") as T;
};

const resultB = defaultValue(); 
console.log(resultB); 
// Output: Test TypeScript Generics

If a type is not explicitly provided, it defaults to string:

Why Would I Consider Using TypeScript Generics with Arrow functions

  • They add code reusability and use the same function with different types without having to rewrite it.
  • TypeScript type safety is enhanced and you don’t misuse functions with incompatible types.
  • I get the flexibility to design functions with adapt data types without sacrificing type safety.

Conclusion

TypeScript Generic Arrow Functions are great shorthand. It’s them you need flexibility and type safety while still working with different types and not sacrificing type information.

Happy future generic TypeScript arrow functions!

How to Create TypeScript Generic Arrow Function

Written By:

Joseph Chege