Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

either #24

Merged
merged 24 commits into from
Feb 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
fda2c09
feat: implement fold method either monad
VKTRenokh Feb 17, 2024
b4fa594
feat: implement map method
VKTRenokh Feb 17, 2024
91e56b0
refactor: move either monad to a separate directory
VKTRenokh Feb 17, 2024
b0ba718
feat: implement from-throwable for either monad
VKTRenokh Feb 17, 2024
ec9f2f5
feat: add from-throwablee test
VKTRenokh Feb 17, 2024
1df5db9
feat: add jsdoc for from-throwable either
VKTRenokh Feb 17, 2024
91c7757
refactor: move maybe to separate directory
VKTRenokh Feb 17, 2024
4260cf6
docs: update readme.md
VKTRenokh Feb 17, 2024
2c98db9
feat: implement flat map method for either monad
VKTRenokh Feb 17, 2024
86c61f9
feat: implement either .map method test
VKTRenokh Feb 18, 2024
c1c9268
feat: add either.left tests for map
VKTRenokh Feb 18, 2024
81497cf
feat: implement either flat map test
VKTRenokh Feb 18, 2024
7bb87a3
feat: implement filterOrElse method
VKTRenokh Feb 18, 2024
ea1d04c
feat: implement filter or else test
VKTRenokh Feb 18, 2024
7f258d2
docs: add either examples
VKTRenokh Feb 18, 2024
f5e5862
feat: add jsdoc for Right, Left interface methods
VKTRenokh Feb 18, 2024
7e3e3fb
feat: add jsdoc for right, left functions
VKTRenokh Feb 18, 2024
31f3ded
refactor: rename filterOrElse function
VKTRenokh Feb 19, 2024
ea473e3
feat: add changesets
VKTRenokh Feb 19, 2024
b8b0af2
fix: ensureOrElse tests
VKTRenokh Feb 19, 2024
bbb2b49
feat: add from maybe util function
VKTRenokh Feb 19, 2024
79b42e7
feat: add to-maybe util function
VKTRenokh Feb 19, 2024
011a57d
docs: add toMaybe, fromMaybe examples
VKTRenokh Feb 19, 2024
cbc401f
feat: add fromMaybe, toMaybe tests
VKTRenokh Feb 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/bright-terms-leave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@victorenokh/maybe.ts": patch
---

Rename filterOrElse method to ensureOrElse
5 changes: 5 additions & 0 deletions .changeset/rare-mangos-guess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@victorenokh/maybe.ts": minor
---

Implemented either monad, changed monads structure
5 changes: 5 additions & 0 deletions .changeset/strong-pears-fail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@victorenokh/maybe.ts": minor
---

Added toMaybe, fromMaybe util functions
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ module.exports = {
],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/explicit-function-return-type':
'off',
'@typescript-eslint/explicit-module-boundary-types':
Expand Down
155 changes: 8 additions & 147 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,151 +1,12 @@
# Maybe Monad In Typescript
# @victorenokh/maybe.ts

maybe monad implementation in typescript with great types and some utils
# Installation
To install the stable version:
`npm i @victorenokh/maybe.ts`

# Examples
- [Maybe](./examples/maybe.md)
- [Either](./examples/either.md)

## .map()
```ts
maybe(42).map(num => num * 2).map(console.log) // Output: 84
```
## .tap()
``` ts
maybe(42).tap(console.log).map(num => num * 2).tap(console.log) // Output: 42 then 84

```

## .mapNullable()
```ts
const getOrNothing = (num) => num > 2 ? null : num

const a = maybe(4).map(getOrNothing) // type is Maybe<number | null>
const a = maybe(4).mapNullable(getOrNothing) // type is Maybe<number>
```

## .asyncMap()
```ts
const sleep = (ms: number): Promise<number> =>
new Promise((res) => setTimeout(() => res(ms), ms));

maybe(1000)
.asyncMap((ms) => sleep(ms))
.then((maybeTime) => {
maybeTime.map(console.log); // 1000 after 1 second
});
```

## .flatMap()
```ts
maybe(42).flatMap((num) => maybe(num + 5)).map(console.log) // 47

const getNumber = () => Math.random() > 0.5 ? 1 : undefined

maybe(42)
.flatMap((num) =>
undefinedToMaybe(getNumber()).map((secondNum) => secondNum + num),
)
.map(console.log) // 43 or nothing
```

## .equals()
```ts
const a = maybe(24)
const b = maybe(24)
const c = maybe('Hello!')

console.log(a.equals(b)) // true
console.log(a.equals(c)) // false
```


## .getOrElse()
```ts
const value = maybe<string>(null).getOrElse('default string') // value is 'default string'
const value1 = maybe<string>('some string').getOrElse('default string') // value is 'some string'
```

## .flatGetOrElse()
```ts
const value = maybe<number>(null).flatGetOrElse(maybe(42)) // value is 42
const value = maybe(53).flatGetOrElse(maybe(42)) // value is 42
```

## .merge()
```ts
const a = maybe('something')
const b = maybe('something again')

const merged = a.merge(b).map(console.log) // { left: "something", right: "something again" }
```
if something doesn't have value
```ts
const a = maybe<string>(null)
const b = maybe('something again')

const merged = a.merge(b).map(console.log) // nothing happens
```

## undefinedToMaybe()
```ts
const getNumberOrUndefined = () => Math.random() > 0.5 ? 5 : undefined

const number = undefinedToMaybe(getNumberOrUndefined())

number.map(console.log) // 5 or nothing
```

## merge()
```ts
const a = maybe(5)
const b = maybe('hello')
const c = maybe({someKey: 'someValue'})

const merged = merge(a, b, c) // type is Maybe<[number, string, {someKey: 'someValue'}]>

merged.map(console.log) // [5, 'hello', { someKey: 'someValue' }] or if some maybe is nothing, nothing going to happen
```

# mergeMap()
```ts
const add = (a: number, b: number) => a + b

const a = maybe(5)
const b = maybe(100)

const final = mergeMap(a, b, add)

final.map(console.log) // 105 or if some maybe is nothing, nothing going to happen
```

# call()
```ts
const mfn = maybe(() => console.log('hello world'))

mfn.map(call) // hello world
```

# or()
```ts
const a = maybe<number>(null)
const b = maybe(5)
const c = maybe(6)

const final = or(a, b, c)

final.map(console.log) // 5
```

# fromThrowable()
```ts
const throwable = (num: number) => {
if (num > 0.5) {
throw new Error('number is greater than 0.5')
}

return ':)'
}

const something = fromThrowable(throwable)

something(Math.random()).tap(console.log) // :) or nothing
```
# License
The MIT License (MIT)
82 changes: 82 additions & 0 deletions examples/either.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Either Examples
## .map()
```ts
E.right(1)
.map(double)
.fold(() => {}, console.log) // Output: 2
```

## .flatMap()
```ts
const getMoreThan = (
num: number,
): E.Either<string, number> => {
const random = Math.random()

if (random > num) {
return E.left(`random is greater than ${num}`)
}

return E.right(random)
}

getMoreThan(0.5)
.flatMap((num) => getMoreThan(num + 0.01))
.fold(console.error, console.log) // random number, or error in console
```

## .isRight()
```ts
console.log(left('test').isRight()) // Output: false
console.log(right('test').isRight()) // Output: true
```

## .isLeft()
```ts
console.log(left('test').isLeft()) // Output: true
console.log(right('test').isLeft()) // Output: false
```

## .ensureOrElse()
```ts
const user = {
has2Fa: true,
name: '12',
}

const validate = (u: typeof user) => u.has2Fa
const validateName = (u: typeof user) => u.name.length >= 3

const a: Either<string, typeof user> = right(user)

const b = a
.ensureOrElse(validate, () => 'user does not have 2 fa')
.ensureOrElse(
validateName,
() => 'user name is too small',
)

b.fold(
(e) => console.error(e),
(b) => console.log(b),
i) // Output: user name is too small
```

## toMaybe()
```ts
toMaybe(left<string, number>('left')).tap(console.log) // nothing happens
toMaybe(right<number, string>(50)).tap(console.log) // Output: 50
```

## fromMaybe()
```ts
fromMaybe(of(50), 'maybe is nothing').fold(
console.error,
console.log,
) // Output: 50

fromMaybe(none<number>(), 'maybe is nothing').fold(
console.error,
console.log,
) // Output: error maybe is nothing
```
Loading