At Agira, Technology Simplified, Innovation Delivered, and Empowering Business is what we are passionate about. We always strive to build solutions that boost your productivity.

Easy Functional Programming Techniques In TypeScript

  • By Manikandan Thangaraj
  • January 13, 2020
  • 996 Views

Over the past years, Functional programming has become a really hot topic in the JavaScript world. Functional programming allows us to build better software without designing complex classes and functions. But it is also not a silver bullet like other programming paradigms/styles. Functional programming also has its own pros and cons.
If you are JavaScript/TypeScript developer who wants to learn functional programming, No worries cause you don’t have to learn other functional programming oriented languages since JavaScript covers some of the coolest concepts. Today, I’ am going to explain some cool functional programming concepts with TypeScript.

What is Functional Programming?

Functional programming is a programming paradigm—a style of building the structure and elements of computer programs—that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data.
Wikipedia

Let us try breaking the definition into parts,

  • Functional programming is a programming paradigm or pattern; means defining some fundamental principles to construct a better program.
  • It treats computation as the evaluation of mathematical functions.
  • It avoids shared state, changing-state, mutable data, and side-effects.
  • It is declarative rather than imperative and application state shares through pure functions.

Hence in functional programming, there are a few very important rules:

  • Pure functions – is a function that should be given the same input, will always return the same output with no side effects.
  • Function composition – is the process of combining two or more functions to produce a new function.
  • Avoid shared state – the Shared state is any variable, object, or memory space that exists in a shared scope, or as the property of an object being passed between scopes.
  • Avoid mutating state – it causes state changes without making component re-render.
  • Avoid side effects – A function or operation should not change any state outside of its functional scope

Below are some of the functional programming concepts that can be applied in TypeScript, we will get it all one by one.

  • Higher-order-functions
  • Closures
  • Currying
  • Recursion
  • Lazy evaluations
  • Referential transparency

Functional programming in TypeScript

TypeScript is not a purely functional programming language but offers a lot of concepts that behave like functional programming. Let’s see how we can apply those concepts in TypeScript and also you can do the same in JavaScript as we all know TypeScript is just a superset of JavaScript.

Higher-order-functions

Higher-order functions can be assigned to variables, passed as an argument to another function or return as another function’s return result. A higher-order function takes one or more functions as parameters or functions as a return.
In TypeScript, this is quite easy to do. Take a look.

type mapFn = (it: string) => string;
// This higher-order-function takes an array and a function as arguments. Anf the function should have string as return type.
function mapForEach(arr: string[], fn: mapFn): string[] {
    const newArray: string[] = [];
    arr.forEach(it => {
        // We are executing the method passed
       newArray.push(fn(it));
    });
    return newArray;
}
const list = ["Orange", "Apple", "Banana", "Grape"];
function findLength (it: string): string {
 return it + ' = ' + it.length;
}
// we are passing the array and a function as arguments to mapForEach method.
const out = mapForEach(list, findLength);
console.log(out); // [ 'Orange = 6', 'Apple = 5', 'Banana = 6', 'Grape = 5' ]

Also, we can do this easily by a couple of lines using the JavaScript function map like below.

const list = ["Orange", "Apple", "Banana", "Grape"];
// we are passing a function as arguments to the built-in map method.
const out = list.map(it => it + ' = ' + it.length);
console.log(out); // [ 'Orange = 6', 'Apple = 5', 'Banana = 6', 'Grape = 5' ]

There are also many built-in declarative higher-order-functions in TypeScript/JavaScript like a map, reduce, forEach, filter and so on. There are many libraries that provide functional interfaces to be used with TypeScript/JavaScript.

Pure functions

Like I already explained, the pure function should return the values only based on the parameters of the function and it shouldn’t depend or affect the global scope values. See the below example for simply getting two numbers as arguments and returning output based only on those arguments. So this behavior is highly predictable. And it won’t affect by global scope.

function add(a: number, b: number): number {
  return a + b;
}

If we add an extra line in this function, the behavior becomes unpredictable and it will affect by the external state. in this case, the behavior becomes unpredictable.

const holder = {};
function add(a: number, b: number): number {
    let c = a + b;
    holder[`${a}+${b}`] = c;
    return c;
}

So try to keep your functions pure and simple.

Recursion

Functional programming also supports recursion over looping concepts. Let’s look at an example for calculating the factorial of a number.
In a traditional iterative approach,

function factorial(num: number): number {
  let result = 1;
  for (; num > 0; num--) {
      result *= num;
  }
  return result;
}
console.log(factorial(20));

The same recursion can be done with Functional Programming favored as below.

const factorial = (num: number): number =>
    num == 0 ? 1 : num * factorial(num - 1);
console.log(factorial(20)); // 2432902008176640000

Lazy evaluation

Lazy evaluation or non-strict evaluation is a strategy that holds the evaluation of an expression until it is needed. TypeScript is strict evaluation but operands like &&, || and ?: it does a lazy evaluation.
See the below example for an eager evaluation in TypeScript.

function add(x: number): number {
  console.log("executing add"); // this is printed since the functions are evaluated first
  return x + x;
}
function multiply(x: number): number {
  console.log("executing multiply"); // this is printed since the functions are evaluated first
  return x * x;
}
function addOrMultiply(
  add: boolean,
  onAdd: number,
  onMultiply: number
): number {
  return add ? onAdd : onMultiply;
}
console.log(addOrMultiply(true, add(4), multiply(4))); // 8
console.log(addOrMultiply(false, add(4), multiply(4))); // 16

This will provide below output:

// OUTPUT
executing add
executing multiply
8
executing add
executing multiply
16

We can change this in into lazily evaluated version using higher-order functions,

function add(x: number): number {
  console.log("executing add");
  return x + x;
}
function multiply(x: number): number {
  console.log("executing multiply");
  return x * x;
}
type fnType = (t: number) => number;
// This is now a higher-order-function hence evaluation of the functions are delayed in if-else
function addOrMultiply(
  add: boolean,
  onAdd: fnType,
  onMultiply: fnType,
  t: number
): number {
  return add ? onAdd(t) : onMultiply(t);
}
console.log(addOrMultiply(true, add, multiply, 4));
console.log(addOrMultiply(false, add, multiply, 4));

This will output like this,

// OUTPUT
executing add
8
executing multiply
16

Above you can see they won’t change immediately and it will wait until it’s required.

Referential transparency

Referential transparency is an expression that means it can be replaced with its corresponding value without changing the program’s behavior. It required that the expression should be pure function so it won’t cost any side effects.
But in JavaScript we don’t have many ways to strictly limit data mutation, however by using pure functions we can achieve this and also we can use Immutable JS. Using const we can avoid reassignments.
For example, below will throw an error,

const list = ["Apple", "Orange", "Banana", "Grape"];
list = ["Earth", "Saturn"];

But it won’t help for an object for example we can push data to const array variables using push so see below mutation will work irrespective.

onst list = ["Apple", "Orange", "Banana", "Grape"];
list.push("Earth"); // will mutate the list
list.push("Saturn"); // will mutate the list

Other ways, we can use Object.freeze or built-in methods like map, reduce, filter and so on as they do not mutate the data.
I hope this introduction on function programming helped you in understanding the concept, rules and how to apply some functional programming techniques in TypeScript.
Like reading related content on Javascript? Get some amazing blogs over here!
Looking for innovative development ideas you can incorporate in your business? Our Web development services can help. Hire JavaScript developers who are best in the industry today!

Turn your vision to magnificent reality With
Our Web and Mobile Solutions

Manikandan Thangaraj

A Passionate full stack developer with 9 years of experience in full stack web application development and expertise in technologies like PHP and Angular. He has huge craze in learning new things about technologies and constantly shares his knowledge with others.