Password   Vegas2024

SSID            DevfestSXB

fp-ts

Quand TypeScript devient

fonctionnel

Jordane Grenat

Johan Rouve

Bastien Tran

Agenda

09h00 - Introduction

09h15 - Partie pratique

12h00 - Fin de l'atelier

Programmation fonctionnelle ?

  • Fonctions
  • Pas d'effets de bord
const square = (n) => n * n;

const numbers = [1, 2, 3, 4, 5];
const result = number.map(square);

// [1, 4, 9, 16, 25]
const allItems = [];

const createToDoItem = (name) => {
  const todoItem = {
    name: name,
    status: 'to do'
  };
  
  await db.save(todoItem);
  
  console.log(todoItem);
  
  allItems.push(todoItem);
  
  return todoItem;
}


const createToDoItem = (name) => {
  const todoItem = {
    name: name,
    status: 'to do'
  };
  
  await db.save(todoItem);
  
  console.log(todoItem);
  

  
  return todoItem;
}


const createToDoItem = (name) => {
  const todoItem = {
    name: name,
    status: 'to do'
  };
  
  await db.save(todoItem);
  

  

  
  return todoItem;
}


const createToDoItem = (name) => {
  const todoItem = {
    name: name,
    status: 'to do'
  };
  

  

  

  
  return todoItem;
}

Outils

  • fonctions
  • map, filter, reduce
  • Functor
  • Applicative
  • Monad
const numbers = [1, 2, 3, -2, 4, 5, 8];

const result = numbers
	.filter(isEven)
	.map(square);

// [4, 4, 16, 64];
const numbers = [1, 2, 3, -2, 4, 5, 8];

const result = dedupe(numbers
	.filter(isEven)
	.map(square));

// [4, 16, 64];
const filter = (fn) => (array) => // ...

filter(isPair)([1, 2, 3]);

Currification

const keepEven = filter(isPair);

keepEven([1, 2, 3]);

Pipe

const numbers = [1, 2, 3, 2];

const result = numbers
	|> filter(isPair)
	|> map(double)
	|> dedupe
(numbers)
([2, 2])
([4, 4])

fp-ts

Disclaimer. Teaching functional programming is out of scope of this project, so the documentation assumes you already know what FP is.

It includes the most popular data types, type classes, and abstractions from languages like Haskell, PureScript, and Scala.

const numbers = [1, 2, 3, 2];

const result = numbers
	|> filter(isPair)
	|> map(double)
	|> dedupe
import * as A from 'fp-ts/Array';
import { pipe } from 'fp-ts/function';

const numbers = [1, 2, 3, 2];

const result = pipe(
  numbers,
  A.filter(isPair),
  A.map(double),
  dedupe,
);
import { pipe } from 'fp-ts/function';
import * as A from 'fp-ts/Array';
import * as NEA from 'fp-ts/NonEmptyArray';

Normes d'import

Modules

  • Array
  • NonEmptyArray
  • Option
  • Either
  • Record
  • Task
  • Reader
  • ...

Option

const findUser = (userId: number): User | undefined => {
  // ...
};
const findUser = (userId: number): Option<User> => {
  // ...
};
type Option<A> = 
  | { _tag: 'Some', value: A } 
  | { _tag: 'None' };
import * as O from 'fp-ts/Option';

const username = pipe(
  userId,
  findUser,
  O.map(user => user.name)
);

Tous en boite !

Option : une boîte contenant zéro ou une valeur

Array : une boîte contenant zéro, une ou plusieurs valeurs du même type

NonEmptyArray : une boîte contenant une ou plusieurs valeurs du même type

map : transformer ce qu'il y a dans la boite

  1. Cloner le repository
  2. npm install
  3. npm run test
  4. Réactiver les test un à un
  5. Les faire passer au vert

Password   Vegas2024

SSID            DevfestSXB

Une boîte contenant une valeur d'un type ou d'un autre

Either

type Either<E, A> = Left<E> | Right<A>

Très souvent, le Either représente une erreur : soit tout est Right, soit on a une erreur en Left.

Une boîte qui contient ou contiendra une valeur

Task

type Task<A> = () => Promise<A>

Une Task ne peut pas échouer

Une boîte qui contient ou contiendra une valeur d'un type E ou d'un type A

TaskEither

type TaskEither<E, A> = () => Either<E, A>
Made with Slides.com