TS Belt - fast, modern, and practical utility library for FP in TypeScript
Tags: typescript, javascript, functional, programming
Published: 2021-12-06 20:17:46



![ts-belt - fast, modern, and practical utility library for FP in TypeScript](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/72zizllqdz53a0e5f5ij.png)

**Repo:** https://github.com/mobily/ts-belt

**Documentation:** https://mobily.github.io/ts-belt/

## Introduction

After a few intensive months of after-hours work, I have finally published a new version of `ts-belt` (v3). As stated in the post title, **TS Belt** is a fast, modern, and practical utility library for functional programming in TypeScript.

## Technical Background

TS Belt has been built in [ReScript](https://rescript-lang.org/) (and its [Belt](https://rescript-lang.org/docs/manual/latest/api/belt) stdlib). ReScript generates highly performant JavaScript code, as well as it automatically generates TypeScript types with [genType](https://rescript-lang.org/docs/gentype/latest/introduction). Moreover, I've added a few codemods to the building process to provide even more code optimizations and cleaner TypeScript signatures. 

## Usage

If you're into FP and use TypeScript on a daily basis work, I assume you know at least one of these: 
- Ramda
- Rambda
- Remeda
- lodash/fp

All of them follow FP principles: `pipe` operator, immutable data, no side-effects, etc. TS Belt does the same, however it provides the `data-first` approach for a single function call, which feels more natural, makes your code more readable and it’s much more developer-friendly, and the data-last approach for usage within the pipeline. Take a look at the following examples to see the difference:

```ts
// ⬇️ ts-belt → single function call
A.map([1, 2, 3, 4], value => value * 3)

// ⬇️ ramda/rambda → single function call
map(value => value * 3, [1, 2, 3, 4])

// ⬇️ ts-belt → pipe
pipe(
  [1, 2, 3, 4],
  A.filter(value => value % 2 === 0),
  A.map(value => value * 3),
)

// ⬇️ ramda/rambda → pipe
pipe(
  filter(value => value % 2 === 0),
  map(value => value * 3),
)([1, 2, 3, 4])

// ⬇️ lodash/fp → pipe
_.flow(
  _.filter(value => value % 2 === 0),
  _.map(value => value * 3),
)([1, 2, 3, 4])
```

Last but not least, TS Belt provides two interesting implementations of data types:
- [Option](https://mobily.github.io/ts-belt/api/option) - represents the existence and nonexistence of a value by wrapping it with the Option type
- [Result](https://mobily.github.io/ts-belt/api/result) - describes the result of a certain operation without relying on exceptions

## Performance

TS Belt is super fast, and I really mean it, it's even faster than the fastest library so far, Rambda.

Sample results (tested on MacBook Pro, M1 Pro, 2021):

```bash
map (single function call)

✔  @mobily/ts-belt  82,703,682.92  ops/sec  ±0.83%  (96 runs)  fastest
✔  remeda            2,966,512.35  ops/sec  ±1.53%  (92 runs)  -96.41%
✔  ramda            19,918,582.19  ops/sec  ±0.55%  (97 runs)  -75.92%
✔  rambda           81,584,073.11  ops/sec  ±0.88%  (87 runs)  -1.35%
✔  lodash/fp        13,133,226.26  ops/sec  ±0.59%  (99 runs)  -84.12%

filter (single function call)

✔  @mobily/ts-belt  48,676,101.83  ops/sec  ±0.29%  (100 runs)  fastest
✔  remeda            2,588,688.05  ops/sec  ±1.49%  (98 runs)   -94.68%
✔  ramda            16,662,990.83  ops/sec  ±0.78%  (97 runs)   -65.77%
✔  rambda           46,443,339.53  ops/sec  ±1.91%  (99 runs)   -4.59%
✔  lodash/fp         6,620,795.22  ops/sec  ±0.79%  (96 runs)   -86.40%

reduce (single function call)

✔  @mobily/ts-belt  44,890,901.88  ops/sec  ±0.17%  (102 runs)  fastest
✔  remeda            2,660,391.00  ops/sec  ±0.82%  (99 runs)   -94.07%
✔  ramda            10,199,240.77  ops/sec  ±0.65%  (97 runs)   -77.28%
✔  rambda           15,497,091.42  ops/sec  ±1.86%  (92 runs)   -65.48%
✔  lodash/fp         9,658,372.21  ops/sec  ±1.08%  (100 runs)  -78.48%

groupBy (single function call)

✔  @mobily/ts-belt  6,453,084.49  ops/sec  ±0.14%  (97 runs)  fastest
✔  remeda           1,783,616.20  ops/sec  ±1.05%  (95 runs)  -72.36%
✔  ramda            1,667,720.10  ops/sec  ±1.30%  (93 runs)  -74.16%
✔  rambda           6,100,470.04  ops/sec  ±1.29%  (94 runs)  -5.46%
✔  lodash/fp        3,123,622.49  ops/sec  ±0.89%  (97 runs)  -51.59%
```

```bash
map → filter → reduce

✔  @mobily/ts-belt  254,251.22  ops/sec  ±0.20%  (99 runs)   fastest
✔  remeda            25,231.20  ops/sec  ±1.76%  (92 runs)   -90.08%
✔  ramda            131,950.08  ops/sec  ±0.41%  (98 runs)   -48.10%
✔  rambda           250,385.53  ops/sec  ±0.39%  (102 runs)  -1.52%
✔  lodash/fp         66,034.82  ops/sec  ±0.71%  (98 runs)   -74.03%

deepFlat → uniq → groupBy

✔  @mobily/ts-belt  2,297,096.07  ops/sec  ±0.20%  (99 runs)  fastest
✔  remeda             494,070.92  ops/sec  ±2.33%  (98 runs)  -78.49%
✔  ramda              281,192.43  ops/sec  ±0.97%  (93 runs)  -87.76%
✔  rambda           1,767,868.03  ops/sec  ±1.10%  (98 runs)  -23.04%
✔  lodash/fp          528,949.75  ops/sec  ±1.15%  (98 runs)  -76.97%
```

Full benchmark results can be found here: https://mobily.github.io/ts-belt/benchmarks/introduction

## Installation

To install `ts-belt` use either `npm` or `yarn`:

```bash
yarn add @mobily/ts-belt
```

```bash
npm install @mobily/ts-belt --save
```

## Final Comments

**TS Belt** combines all of the good things you can find in other similar libraries: the developer-friendly data-first approach, good-looking and detailed documentation, great TypeScript support, and it's fast! 🚀

Let me know if you're willing to use `ts-belt` in your project! Also, don't forget to give a star to `ts-belt` on [Github](https://github.com/mobily/ts-belt). Any feedback or suggestions are appreciated as well.

Happy coding! 😊