Created
January 28, 2022 11:53
-
-
Save kayac-chang/06fdc280357af48f4f68e8af675f27f9 to your computer and use it in GitHub Desktop.
[learn FP with Kirby using `fp-ts`] Option
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { describe } from "../utils"; | |
/** | |
* chain (flatmap) | |
* === | |
* the chain can perform `map` and `flatten` together. | |
*/ | |
import { flow, pipe } from "fp-ts/lib/function"; | |
import * as Option from "fp-ts/Option"; | |
interface Fizz { | |
buzz: string; | |
} | |
interface Foo { | |
bar?: Fizz; | |
} | |
const foo: Foo = { bar: undefined }; | |
describe(`Solution. using chain (flatmap) to improve nested nullable call`, () => | |
pipe( | |
foo, | |
Option.fromNullable, | |
Option.map(({ bar }) => bar), | |
Option.chain( | |
flow( | |
Option.fromNullable, | |
Option.map(({ buzz }) => buzz) | |
) | |
) | |
)); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { describe } from "../utils"; | |
/** | |
* flatten | |
* === | |
* handle where object has sequentially nested nullable properties. | |
* | |
*/ | |
import { pipe } from "fp-ts/lib/function"; | |
import * as Option from "fp-ts/Option"; | |
interface Fizz { | |
buzz: string; | |
} | |
interface Foo { | |
bar?: Fizz; | |
} | |
const foo: Foo = { bar: undefined }; | |
describe(`Question. try to solve this by nested fromNullable`, () => | |
pipe( | |
foo, | |
Option.fromNullable, | |
Option.map(({ bar }) => | |
pipe( | |
bar, | |
Option.fromNullable, | |
Option.map(({ buzz }) => buzz) | |
) | |
) // { _tag: 'Some', value: { _tag: 'None' } } | |
)); | |
describe(`Solution. flatten to recure`, () => | |
pipe( | |
foo, | |
Option.fromNullable, | |
Option.map(({ bar }) => | |
pipe( | |
bar, | |
Option.fromNullable, | |
Option.map(({ buzz }) => buzz) | |
) | |
), | |
Option.flatten | |
// { _tag: 'None' } | |
)); | |
/** | |
* `flatten` take the last `Option` in the pipeline. | |
*/ | |
describe(`if we wanted to check result 'Option' was 'Some' or 'None'`, () => | |
pipe( | |
foo, | |
Option.fromNullable, | |
Option.map(({ bar }) => | |
pipe( | |
bar, | |
Option.fromNullable, | |
Option.map(({ buzz }) => buzz) | |
) | |
), | |
Option.flatten, | |
Option.isSome // false | |
// Option.isNone // true | |
)); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { pipe } from "fp-ts/lib/function"; | |
import { describe } from "../utils"; | |
/** | |
* Option (Maybe) | |
* === | |
* Option are containers that wrap values that could be either `undefined` or `null`. | |
* | |
* if the value exists, | |
* we say the Option is of the `Some` type. | |
* if the value is `undefined` or `null`, | |
* we say it has the `None` type. | |
*/ | |
import * as Option from "fp-ts/Option"; | |
type Fn<A, B> = (a: A) => B; | |
interface Foo { | |
bar: string; | |
} | |
const maybeGetFoo: Fn<void, Foo | undefined> = () => | |
Math.random() < 0.5 ? { bar: "hello" } : undefined; | |
describe(`Example 1. handle the possibly undefined with optional chaining`, () => | |
pipe(maybeGetFoo(), (f) => f?.bar)); // hello | |
describe(`Example 2. we want to avoid introduce variable 'f', but we got type error`, () => | |
pipe(maybeGetFoo(), ({ bar }) => bar)); //! type error | |
/** | |
* Why should we use Option instead of `optional chaining` or `nullish coalescing`. | |
* | |
* below introduce why Option more powerful than build-in. | |
*/ | |
describe(`Solution 1. Option to rescue with 'map' function`, () => | |
pipe( | |
maybeGetFoo(), | |
Option.fromNullable, | |
Option.map(({ bar }) => bar) | |
)); | |
/** | |
* if `maybeGetFoo` | |
* return Foo result will be { _tag: 'Some', value: 'hello' } | |
* return undefined result will be { _tag: 'None' } | |
*/ | |
/** | |
* How does `Option.map` work over the `Option` ? | |
* | |
* It works by performing a comparison over the `_tag` property, | |
* if the `_tag` is `Some`, it transforms the value with function passed in `map`, | |
* otherwise, | |
* if the `_tag` is `None`, no operation is performed. | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment