No description
This repository has been archived on 2023-05-29. You can view files and clone it, but cannot push or open issues or pull requests.
Find a file
dependabot[bot] ceb69fe76f
Bump fp-ts from 2.12.0 to 2.12.1 (#33)
Bumps [fp-ts](https://github.com/gcanti/fp-ts) from 2.12.0 to 2.12.1.
- [Release notes](https://github.com/gcanti/fp-ts/releases)
- [Changelog](https://github.com/gcanti/fp-ts/blob/master/CHANGELOG.md)
- [Commits](https://github.com/gcanti/fp-ts/compare/2.12.0...2.12.1)

---
updated-dependencies:
- dependency-name: fp-ts
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-29 08:39:39 +02:00
.github Add dependabot configuration 2022-03-17 16:41:32 +01:00
.vscode 🎉 Initial commit 2020-07-03 18:01:45 +02:00
src 💬 Fix some wording (#25) 2022-04-20 14:41:57 +02:00
.eslintrc.js 🎉 Initial commit 2020-07-03 18:01:45 +02:00
.gitignore 🎉 Initial commit 2020-07-03 18:01:45 +02:00
.nvmrc ⬆️ Upgrade all dependencies 2022-01-11 14:47:57 +01:00
.prettierrc Update prettier rules 2022-04-06 15:26:46 +02:00
jest.config.js Stop failing test because of typescript errors 2022-03-04 11:40:00 +01:00
package.json Bump fp-ts from 2.12.0 to 2.12.1 (#33) 2022-04-29 08:39:39 +02:00
README.md 💬 Fix some wording (#25) 2022-04-20 14:41:57 +02:00
tsconfig.json 🎉 Initial commit 2020-07-03 18:01:45 +02:00
yarn.lock Bump fp-ts from 2.12.0 to 2.12.1 (#33) 2022-04-29 08:39:39 +02:00

Inato fp-ts training

This repo is a work in progress toward having a comprehensive training material to onboard people on using fp-ts efficiently.

The exercises consist of unimplemented functions and their associated failing tests.

But first, it is essential to understand why we are using fp-ts. I suggest you read this article and then start the exercises.

After cloning the repository, setup the project by running

$ yarn

To run the tests, simply run

$ yarn test

You can also run them in watch mode:

$ yarn test:watch

Finally, if you wish to only run the tests for a given exercise exoN, you can run the following:

$ yarn test[:watch] exoN

The exercises are organized into exoN folders and most of what is required to complete each is detailed in the comments.

code style guide

For readability purpose, we replace ReaderTaskEither by rte

  • Use flow instead of pipe when possible

    Why? Using flow reduces the amount of variables to declare in a method, hence the visibility and readability of the code

// Bad
const formatUserPhoneNumber = (user: User) =>
  pipe(user, User.phoneNumber, User.formatPhoneNumber);

// Good
const formatUserPhoneNumber = flow(User.phoneNumber, User.formatPhoneNumber);
  • Avoid using boolean method match when unecessary

    Why? boolean.match can lower the global understanding of a method and enforce nested pipes. Using classic if/else is often the best option

// Bad
const triggerEmailCampaign = ({
  user,
  ...emailSettings
}: {
  user: User} & EmailSettings) =>
  pipe(
    user.nationality === 'FR',
    boolean.match(
      () => triggerGlobalEmailCampaign({ to: user.email, emailSettings }),
      () => triggerFrenchEmailCampaign({ to: user.email, emailSettings }),
    ),
  );

// Good
const triggerEmailCampaign = ({
  user,
  ...emailSettings
}: { user: User } & EmailSettings) => {
  if (user.nationality === 'FR') {
    return triggerFrenchEmailCampaign({ to: user.email, emailSettings });
  }
  return triggerGlobalEmailCampaign({ to: user.email, emailSettings });
  • Avoid nested pipes

    Why? They lower global understanding of the code. We allow ourselves 2 levels of piping maximum per function and tend to do atomic functions instead

// Bad
export const convertDollarAmountInCountryCurrency = ({
  countryName,
  amountInDollar,
}: {
  countryName: CountryName;
  amountInDollar: number;
}) =>
  pipe(
    getCountryCode(countryName),
    either.map(
      countryCode =>
        pipe(
          getCountryCurrency(countryCode),
          option.map(
            flow(
              convertFromDollarAmount(amountInDollar),
              convertedAmount =>
                console.log(
                  `converted amount for country ${countryCode} is ${convertedAmount}`,
                ),
              ),
            ),
          ),
        ),
    ),
  );

// Good
export const convertDollarAmountInCountryCurrency = (amountInDollar: number) =>
  flow(
    getCountryCode,
    either.map(convertDollarAmountToCountryCodeCurrency(amountInDollar)),
  );

const convertDollarAmountToCountryCodeCurrency =
  (amountInDollar: number) => (countryCode: CountryCode) =>
    pipe(
      getCountryCurrency(countryCode),
      option.map(convertFromDollarAmount(amountInDollar)),
      option.map(convertedAmount =>
        console.log(
          `converted amount for country ${countryCode} is ${convertedAmount}`,
        ),
      ),
    );