Telerik blogs
JavaScriptT2 Dark_1200x303

Let’s see how we can combine functional programming and TypeScript to build highly reusable and maintainable software.

Learning a programming language is not easy. A programming language has many different concepts and ways of accomplishing something. Every programming language is created following a paradigm.

JavaScript developers, most of the time, tend to use an object-oriented programming approach. Object-oriented programming is still a widely used paradigm in JavaScript, but this is starting to change.

Every day the adoption of functional programming in JavaScript is increasing. Functional programming is a great way to build reusable and maintainable code. It makes heavy use of pure functions, avoids sharing state and mutating data, etc. With more and more content about functional programming in JavaScript, its usage is spreading among the community.

But JavaScript is not a functional programming language. We can say that JavaScript is a multi-paradigm language that allows us to do some functional programming in some parts. We can leverage JavaScript and use it in a way where we can end up with fully functional code.

On the other hand, combining functional programming with TypeScript is an even better match. We combine highly reusable and maintainable code with static types and great tooling.

Today we’re going to cover how we can combine functional programming and TypeScript to build highly reusable and maintainable software.

Functional Programming and TypeScript

Functional programming is a programming paradigm that makes use of functions for creating reusable and maintainable code. The code is created by applying and composing functions, making them reusable and maintainable across the codebase.

The functional programming paradigm is not new—it has been around for decades. Actually, the first programming language was developed in the 1950s. Because of its nature, functional programming has been gaining popularity among developers, especially JavaScript developers.

TypeScript, on the other side, is a superset of JavaScript that adds static types to your code and helps to catch errors early in your editor. It offers great tooling and provides safety to your code, helping you to avoid making silly mistakes and breaking things.

When we combine a great programming paradigm with TypeScript, we can end up with a powerful and safe combination. We can create reusable and maintainable code that is type-safe.

Now, let’s dive deep and start to combine functional programming and TypeScript to see how powerful it is.

A Powerful Combination

Pure Functions

Pure functions are functions that, given a specific input, will always return the same output. A pure function is designed to not cause any side effect. We can understand a side effect here as a modification to an object, reassigning a value, etc.

Pure functions are one of the pillars of functional programming. Functional programming requires us to write pure and deterministic functions.

A simple pure function that sum two numbers would look like this:

const sum = (a: number, b: number): number => a + b;

A great part of creating pure functions with TypeScript is passing the correct types for the function arguments and the function output.

Although TypeScript still does not have a way to fully assure that a function is pure (there’s a discussion about adding a pure keyword to handle pure functions), we can make sure that we have a pure function when:

  • We have a function that returns the same output given an input.
  • It does not mutate any data.
  • It does not create any side effect.

Using pure functions with TypeScript can make our code better. Pure functions are perfect for creating maintainable, reusable and testable code. We can simulate and predict the behavior of a pure function, making predictability easier. Since it doesn’t create any side effects, we can ensure the result will be the one expected.

Higher-Order Functions

A higher-order function is a function that receives another function as a parameter or returns a function as a return value. They are called “higher-order” because they are functions that operate on other functions.

They allow us to combine simple functions in a sophisticated way. Higher-order functions are another very important concept in the functional programming paradigm.

const greaterThan = (n: number) => {
  return (x: number) => x > n;
};

const greaterThanTwo = greaterThan(10);

We created a function that receives a number and compares if the number passed is greater than the other number. We can use TypeScript to make sure that every parameter of our function receives the respective type.

Another great way to create high-order functions using TypeScript is to make use of generics. Generics allows us to create reusable functions using a variety of types.

For example, imagine that we’re going to create a function that returns another function, which divides two numbers. Sound complex? It is easy to accomplish this with TypeScript and functional programming, take a look:

type MyFunc<T> = (s: T) => (c: number) => number;

const genericFunc: MyFunc<number> = (n: number) => (c: number) => n / c;

Function Composition

Functional programming is a programming paradigm that makes use of pure functions. The code is created by applying and composing functions, so knowing how to compose functions is very important.

Pure functions can’t access external data by definition, so they’re easy to compose and reuse across the code.

Piping is a process of returning the output of a function and passing it to another function. It creates a chain of functions—something like this:

result = input -> firstFunction -> secondFunction -> thirdFunction

Many programming languages have something called the pipe operator. It makes it easier to compose many functions. The pipe takes the result on the left, and passes it to the right-hand side. Here’s an example of how the pipe operator works in Elixir:

result() 
  |> firstFunction() 
  |> secondFunction() 
  |> thirdFunction()

Unlike many functional programming languages, JavaScript does not (yet) have the pipe operator, and trying to implement piping in JavaScript can get ugly easily. Look how hard it is to actually understand what is going on in this code:

const result = firstFunction(secondFunction(thirdFunction(input)));

Here’s how we can implement function composition using TypeScript:

const sum = (n: number) => n + 10;
const double = (n: number) => n * 2;
const divide = (n: number) => n / 2;

This code is still not good enough. What we can do now is create a higher-order function that takes many functions and returns a single function that combines them all. We’re going to use the reduce method for that, and here’s how is going to work:

const combine = (result, nextFun) => nextFun(result);

const pipe = (...fns) => x => fns.reduce(combine, x);

Now, we can create a better function composition by simply passing all functions that we want and the arguments that we need, like this:

const result = pipe(sum, double, divide)(10);

Conclusion

JavaScript is the most popular programming language in the world. We can build anything using it, from simple web applications to complex APIs and web services.

TypeScript is a superset of JavaScript that adds safety to our code by making use of static types. Leveraging the usage of JavaScript with TypeScript and functional programming can create a powerful combination. We can create robust applications using TypeScript and functional programming, with reusable and testable code.


Leonardo Maldonado
About the Author

Leonardo Maldonado

Leonardo is a full-stack developer, working with everything React-related, and loves to write about React and GraphQL to help developers. He also created the 33 JavaScript Concepts.

Related Posts

Comments

Comments are disabled in preview mode.