Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/stevemao/fp-ts-extras
fp-ts extra functions and utilities
https://github.com/stevemao/fp-ts-extras
fp fp-ts functional-programming hacktoberfest
Last synced: 29 days ago
JSON representation
fp-ts extra functions and utilities
- Host: GitHub
- URL: https://github.com/stevemao/fp-ts-extras
- Owner: stevemao
- Created: 2020-10-24T11:49:19.000Z (about 4 years ago)
- Default Branch: master
- Last Pushed: 2021-10-02T10:08:06.000Z (about 3 years ago)
- Last Synced: 2024-10-12T00:58:49.375Z (about 1 month ago)
- Topics: fp, fp-ts, functional-programming, hacktoberfest
- Language: TypeScript
- Homepage:
- Size: 1.03 MB
- Stars: 6
- Watchers: 3
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: Readme.md
Awesome Lists containing this project
README
> fp-ts extra functions and utilities
## Array
### groupBy
```ts
import { groupBy } from "fp-ts-extras/lib/Array";assert.deepStrictEqual(groupBy(eqNumber)([1, 1, 2, 3, 3, 4]), [
[1, 1],
[2],
[3, 3],
[4],
]);
```## Option
### partial
> Drop-in replacement of `t.partial`
Instead of returning `A | undefined`, it returns `Option`
```ts
import { partial } from "fp-ts-extras/lib/Option";const B = partial({
bar: t.number,
});
``````ts
import * as t from "io-ts";const User = t.type({
userId: t.number,
name: t.string,
});const PartialUser = t.partial(User.props);
type PartialUser = t.TypeOf;
// same as
type PartialUser = {
name: Option;
age: Option;
};
```## Function
### memPipe
Problem: I have a `task` and if I call
```ts
task();
task();
```it fires the internal promise twice. The expected behaviour is it should only fire once. The second call returns the same result as the first one.
Use case: I have 3 tasks: `t1`, `t2`, `t3`. `tA` is called once `t1` and `t2` is done. `tB` is called once `t1` and `t3` is done. `tC` is called once `t2` and `t3` is done. With raw promise I could do
```ts
Promise.all([
Promise.all([t1, t2]).then(_ => tA)
Promise.all([t2, t3]).then(_ => tC)
Promise.all([t1, t3]).then(_ => tB)
]).then(...)
```But with Task
```ts
sequence([
pipe(sequence([t1, t2])), chain(_ => tA)),
pipe(sequence([t2, t3]), chain(_ => tC)),
pipe(sequence([t1, t3]), chain(_ => tB)),
])
...
```side effects of `t1`, `t2`, `t3` will be fired twice each. `memPipe` will come in handy
```ts
import { memPipe } from "fp-ts-extras/lib/Function";const t1 = memPipe(...)
const t2 = memPipe(...)
const t3 = memPipe(...)sequence([
pipe(sequence([t1, t2])), chain(_ => tA)),
pipe(sequence([t2, t3]), chain(_ => tC)),
pipe(sequence([t1, t3]), chain(_ => tB)),
])
```Each task only performs side effect once.
## JSON
> encode/decode automatically when you stringify/parse
Why? You can use your preferred algebraic data types in your business logic, and can be converted to traditional json automatically when you do http request or save stuff to db, and vice versa.
```ts
const T = t.type({
foo: optionFromNullable(t.string),
});const result = stringify(T, {
foo: O.of("abc"),
});
// right '{"foo":"abc"}'const result = parse(T, '{"foo":"abc"}');
/*
right {
foo: O.of("abc"),
}
*/
```## Record
### union
```ts
import { union } from "fp-ts-extras/lib/Record";assert.deepStrictEqual(
union([
{
foo: "foo",
},
{
bar: "bar",
},
]),
{
foo: "foo",
bar: "bar",
}
);
```## String
```ts
import { split, join } from "fp-ts-extras/lib/String";
import { pipe } from "fp-ts/lib/Function";
import * as assert from "assert";const result = pipe("a,b,c", split(","), join(":"));
assert.deepStrictEqual(result, "a:b:c");
```## TaskEither
### decode
> Decode with error to reduce boilerplate
```ts
import { decode } from "fp-ts-extras/lib/TaskEither";
import * as t from "io-ts";
import { pipe } from "fp-ts/lib/Function";pipe(
decode(t.string, null)
// compose with other `TaskEither`s
);
```## Tuple
> Various useful functions on tuples, overloaded on tuple size.
## UUID
> UUID generator that returns type `UUID`
# Related projects
- https://github.com/gcanti/fp-ts-contrib
- https://github.com/samhh/fp-ts-std