Maksim I

5. Functional programming in JS/TS

As we have seen from examples before - JS supports main functional principles, but not static types. So, we would talk about the features that TS supports:

But, some features are missed:

5.1 Widespread functional JS libraries

5.1.1 Ramda

Ramda is a library of functions which is written in a purer functional style. Functions are automatically curried. Ramda does not provide any new abstractions or methodologies - just utils.

const double = R.multiply(2);

double(3); // 6

In order to run Listing 4.5 open Try ramda

More info - Ramda

5.1.2 Lodash

lodash/fp module promotes a more functional programming (FP) friendly style by exporting an instance of lodash with its methods wrapped to produce immutable auto-curried iterate-first data-last methods. lodash makes JavaScript easier by taking the hassle out of working with arrays, numbers, objects, strings, etc.

Lodash modular methods are great for:

const users = [
  { user: "barney", age: 36, active: true },
  { user: "fred", age: 40, active: false },
];

_.filter(users, { active: false }); // [{ user: "fred", age: 40, active: false }]

To run Listing 5.1.2 open lodash docs and press the Try in REPL button on any code example.

More info - Lodash.

5.1.3 FP-TS

fp-ts provides developers with popular patterns and reliable abstractions from typed functional languages in TypeScript. In contrast to other libraries enlisted above, fp-ts provides lacked features of JS/TS, such as:

And on the other side, it does not provide some special utils, for example, head, groupBy, drop, multiply, etc. You should implement them by yourself, or use another library from the ecosystem. You can use other libraries as well, such as lodash, ramda, etc. But try not to mix them a lot, and prefer more natural to fp-ts approaches.

import * as O from 'fp-ts/Option';
import { flow } from 'fp-ts/function';

const double = n => n * 2;
const head = <A>(as: ReadonlyArray<A>): O.Option<A> => (as.length === 0 ? O.none : O.some(as[0]));
const inverse = (n: number): O.Option<number> => (n === 0 ? O.none : O.some(1 / n));

const main = flow<ReadonlyArray<number>>(
  head, // get first element
  O.map(double), // double it
  O.chain(inverse), // 1 / n
  O.match(
    () => 'no result', // onNone handler
    (head) => `Result is ${head}` // onSome handler
  ),
);

main([5, 2, 3]); // Result is 0.1
main([]); // no result
main([0]); // no result

5.1.4 React

As you know, React is one of the most popular JavaScript libraries to create Web user interfaces. Its success is due to several factors, but maybe one of them is the clean and effective approach to programming. In the React environment, every piece of a UI is a component. Components can be composed together to create other components. The application itself is a component: a composition of components. For example, Listing 4.7. The task is to create a user form.

import React, { useState } from 'react';
import ReactDOM from 'react-dom';

const Input = ({ value, label, onChange }) => (
  <div>
    <label>
      {label}: <input value={value} onChange={(event) => onChange(event.target.value)}></input>
    </label>
  </div>
);

const ShowButton = ({ onClick, isShowing }) => {
  return (
    <button onClick={onClick}>
      {isShowing ? 'Hide values' : 'Show values'}
    </button>
  );
};

const App = () => {
  const [formState, setFormState] = useState({
    name: '',
    lastName: '',
    email: ''
  });
  const [showValues, setShowValues] = useState(false);
  const toggleValues = () => setShowValues((isShowing) => !isShowing);

  const setStateFor = (field) => (value) =>
    setFormState((state) => ({ ...state, [field]: value }));

  return (
    <div>
      <Input
        value={formState.name}
        label="Name"
        onChange={setStateFor('name')}
      />
      <Input
        value={formState.lastName}
        label="Last name"
        onChange={setStateFor('lastName')}
      />
      <Input
        value={formState.email}
        label="Email"
        onChange={setStateFor('email')}
      />
      <ShowButton onClick={toggleValues} isShowing={showValues}/>
      {showValues ? (
        <ul>
          {Object.entries(formState).map(([field, value]) => (
            <li key={field}>
              {field}: {value}
            </li>
          ))}
        </ul>
      ) : null}
    </div>
  );
};

In the code above, there are three components Input, ShowButton, and Main. By composing components in the Main component a variety of screens can be created. For example, to create different types of Input the props have to be passed instead of creating three different Input elements. The state is immutable and changed only by calling callbacks which re-renders components with just a new state. It is pretty reusable.

You can run this code here: https://codesandbox.io/s/app-zi9cxr.

React is an excellent example of abstracting the side effects of the application. As we know, writing to the DOM and screen is a side effect. And in React, we are not doing it! The logic of our application is fully abstracted, and we define how our UI would look. How it will be rendered is not our concern. Purely to the HTML string? Directly applied to the DOM? Or to the native mobile application? You can choose any variant, and the main logic of your application wouldn’t change.

More info - React.

4.4 Pros and Cons of FP

Pros

Cons