fp-tsのtutorial動画があるが
中身を文字で見たかったが それを公開しているところがなかったので書いてみようと思った
※あまりにも長くなったので分割
動画
Chapter 1: pipe and flow
pipe - [A -> B]
\displaylines{
pipe(A, f) \\
\\
A \xrightarrow{f} B
}
import { describe, it } from 'vitest'
import { pipe } from 'fp-ts/lib/function'
describe('fp-ts Tutorial ', () => {
it('pipe - A -> B', () => {
const size = (s: string) => s.length
console.log(pipe('hello', size))
console.log(size('hello'))
})
})
実行結果
5
5
pipe - [A -> B -> C]
\displaylines{
pipe(A, f, g) \\
\\
A \xrightarrow{f} B \xrightarrow{g} C
}
import { describe, it } from 'vitest'
import { pipe } from 'fp-ts/lib/function'
describe('fp-ts Tutorial ', () => {
it('pipe - A -> B -> C', () => {
const size = (s: string) => s.length
const isAtLeast3 = (n: number) => n >= 3
console.log(pipe('hello', size, isAtLeast3))
console.log(size('hello'))
console.log(isAtLeast3(size('hello')))
})
})
実行結果
true
5
true
pipe - [A -> B -> C -> D]
\displaylines{
pipe(A, f, g, h) \\
\\
A \xrightarrow{f} B \xrightarrow{g} C \xrightarrow{h} D
}
import { describe, it } from 'vitest'
import { pipe } from 'fp-ts/lib/function'
describe('fp-ts Tutorial ', () => {
it('pipe - A -> B -> C -> D', () => {
const trim = (s: string) => s.trim()
const size = (s: string) => s.length
const isAtLeast3 = (n: number) => n >= 3
const value = ' hello '
console.log(pipe(value, trim, size, isAtLeast3))
console.log(value)
console.log(trim(value))
console.log(size(trim(value)))
console.log(isAtLeast3(size(trim(value))))
})
})
実行結果
true
hello
hello
5
true
flow - [A -> B -> C -> D]
\displaylines{
flow(f, g, h) \\
\\
A \xrightarrow{f} B \xrightarrow{g} C \xrightarrow{h} D
}
import { describe, it } from 'vitest'
import { flow } from 'fp-ts/lib/function'
describe('fp-ts Tutorial ', () => {
it('flow - A -> B -> C -> D', () => {
const trim = (s: string) => s.trim()
const size = (s: string) => s.length
const isAtLeast3 = (n: number) => n >= 3
const isValid = flow(trim, size, isAtLeast3)
const value = ' hello '
console.log(isValid(value))
console.log(value)
console.log(trim(value))
console.log(size(trim(value)))
console.log(isAtLeast3(size(trim(value))))
})
})
実行結果
true
hello
hello
5
true
Chapter 2: Option
Option<number>
inverse(x) = \left\{
\begin{array}{ll}
None & (x = 0) \\
\frac{1}{x} & (x \neq 0)
\end{array}
\right.
import { describe, it } from 'vitest'
import * as O from 'fp-ts/Option'
describe('fp-ts Tutorial', () => {
it('Option', () => {
const inverse = (x: number): O.Option<number> => (x === 0 ? O.none : O.some(1 / x))
console.log(inverse(0))
console.log(inverse(2))
})
})
実行結果
{ _tag: 'None' }
{ _tag: 'Some', value: 0.5 }
従来の書き方
x=0の場合は未定義(エラーが出る)
\displaylines{
inverse(x) = \frac{1}{x} \\
(x \neq 0)
}
import { describe, it } from 'vitest'
describe('fp-ts Tutorial', () => {
it('Option', () => {
const inverse = (x: number): number => {
if (x === 0) {
throw Error('Cannot get inverse of 0.')
}
return 1 / x
}
console.log(inverse(2))
console.log(inverse(0))
})
})
実行結果
0.5
実行時にエラーが出る
※'Cannot get inverse of 0.'
O.fold(onNone, onSome)
\displaylines{
inverse(x) = \left\{
\begin{array}{ll}
None & (x = 0) \\
\frac{1}{x} & (x \neq 0)
\end{array}
\right.
\\
getUiMessageWithInverse(x) = \left\{
\begin{array}{ll}
Cannot \hspace{5pt} get \hspace{5pt} the \hspace{5pt} inverse \hspace{5pt} of \hspace{5pt} \check{x} . & (x = 0) \\
The \hspace{5pt} inverse \hspace{5pt} of \hspace{5pt} \check{x} \hspace{5pt} is \hspace{5pt} \check{inverse(x)}. & (x \neq 0)
\end{array}
\right.
}
import { describe, it } from 'vitest'
import * as O from 'fp-ts/Option'
import { pipe } from 'fp-ts/lib/function'
describe('fp-ts Tutorial', () => {
it('Option - O.fold(onNone, onSome)', () => {
const inverse = (x: number): O.Option<number> => (x === 0 ? O.none : O.some(1 / x))
const getUiMessageWithInverse = (x: number): string =>
pipe(
x,
inverse,
O.fold(
() => `Cannot get the inverse of ${x}.`,
(ix) => `The inverse of ${x} is ${ix}.`
)
)
console.log(getUiMessageWithInverse(0))
console.log(getUiMessageWithInverse(2))
})
})
実行結果
Cannot get the inverse of 0.
The inverse of 2 is 0.5.
Option<number> - safe
safeInverse(x) = \left\{
\begin{array}{ll}
0 & (x = 0) \\
\frac{1}{x} & (x \neq 0)
\end{array}
\right.
import { describe, it } from 'vitest'
import * as O from 'fp-ts/Option'
import { identity, pipe } from 'fp-ts/lib/function'
describe('fp-ts Tutorial', () => {
it('Option<number> - safe', () => {
const inverse = (x: number): O.Option<number> => (x === 0 ? O.none : O.some(1 / x))
const safeInverse = (x: number): number =>
pipe(
x,
inverse,
O.fold(() => 0, identity)
)
console.log(safeInverse(0))
console.log(safeInverse(2))
})
})
実行結果
0
0.5
Option<number> - safe - O.getOrElse(onNone)
safeInverse(x) = \left\{
\begin{array}{ll}
0 & (x = 0) \\
\frac{1}{x} & (x \neq 0)
\end{array}
\right.
import { describe, it } from 'vitest'
import * as O from 'fp-ts/Option'
import { pipe } from 'fp-ts/lib/function'
describe('fp-ts Tutorial', () => {
it('Option<number> - safe - O.getOrElse(onNone)', () => {
const inverse = (x: number): O.Option<number> => (x === 0 ? O.none : O.some(1 / x))
const safeInverse = (x: number): number =>
pipe(
x,
inverse,
O.getOrElse(() => 0)
)
console.log(safeInverse(0))
console.log(safeInverse(2))
})
})
実行結果
0
0.5
型変更によるエラー
safeInverse(x) = \left\{
\begin{array}{ll}
invalid & (x = 0) \\
\frac{1}{x} & (x \neq 0)
\end{array}
\right.
赤い背景のところでエラーが出る
import { describe, it } from 'vitest'
import * as O from 'fp-ts/Option'
import { pipe } from 'fp-ts/lib/function'
describe('fp-ts Tutorial', () => {
it('Option<number> - safe - O.getOrElse(onNone)', () => {
const inverse = (x: number): O.Option<number> => (x === 0 ? O.none : O.some(1 / x))
const safeInverse = (x: number) =>
pipe(
x,
- inverse,
O.getOrElse(() => 'invalid')
)
console.log(safeInverse(0))
console.log(safeInverse(2))
})
})
実行結果
invalid
0.5
※VSCodeなどでエラー表示されるが、実行は可能
※Argument of type '(x: number) => O.Option' is not assignable to parameter of type '(a: number) => Option'.
Option<number> - safe - O.getOrElseW(onNone)
safeInverse(x) = \left\{
\begin{array}{ll}
invalid & (x = 0) \\
\frac{1}{x} & (x \neq 0)
\end{array}
\right.
import { describe, it } from 'vitest'
import * as O from 'fp-ts/Option'
import { pipe } from 'fp-ts/lib/function'
describe('fp-ts Tutorial', () => {
it('Option<number> - safe - O.getOrElse(onNone)', () => {
const inverse = (x: number): O.Option<number> => (x === 0 ? O.none : O.some(1 / x))
const safeInverse = (x: number) =>
pipe(
x,
inverse,
O.getOrElseW(() => 'invalid')
)
console.log(safeInverse(0))
console.log(safeInverse(2))
})
})
実行結果
invalid
0.5
※getOrElseW だとエラー表示なし
O.fromNullable(nullableValue)
import { describe, it } from 'vitest'
import * as O from 'fp-ts/Option'
describe('fp-ts Tutorial', () => {
it('O.fromNullable(nullableValue)', () => {
const value1 = 3
const value2 = null
const value3 = undefined
console.log(O.fromNullable(value1))
console.log(O.fromNullable(value2))
console.log(O.fromNullable(value3))
})
})
実行結果
{ _tag: 'Some', value: 3 }
{ _tag: 'None' }
{ _tag: 'None' }
Chapter 2.1: Option map, flatten, chain
配列の先頭取得
import { describe, it } from 'vitest'
import * as O from 'fp-ts/Option'
describe('fp-ts Tutorial', () => {
it('Option - head', () => {
const head = <A>(as: ReadonlyArray<A>): O.Option<A> =>
as.length === 0 ? O.none : O.some(as[0])
console.log(head([5, 6, 7]))
console.log(head([]))
})
})
実行結果
{ _tag: 'Some', value: 5 }
{ _tag: 'None' }
O.map(f)
import { describe, it } from 'vitest'
import * as O from 'fp-ts/Option'
import { pipe } from 'fp-ts/lib/function'
describe('fp-ts Tutorial', () => {
it('O.map(f)', () => {
const head = <A>(as: ReadonlyArray<A>): O.Option<A> =>
as.length === 0 ? O.none : O.some(as[0])
const toUpperCase = (s: string) => s.toUpperCase()
const addPrefix = (prefix: string) => (s: string) => prefix + s
const debug_log = <T>(x: T) => {
console.log(x)
return x
}
const getBestMovie1 = (titles: ReadonlyArray<string>): O.Option<string> =>
pipe(
titles,
debug_log,
head,
debug_log,
O.map((s) => s.toUpperCase()),
debug_log,
O.map((s) => `Best - ${s}`)
)
const getBestMovie2 = (titles: ReadonlyArray<string>): O.Option<string> =>
pipe(
titles,
debug_log,
head,
debug_log,
O.map(toUpperCase),
debug_log,
O.map(addPrefix('Best - '))
)
console.log(getBestMovie1(['An American in Rome', 'Winter Holidays']))
console.log('---------------')
console.log(getBestMovie1([]))
console.log('---------------')
console.log(getBestMovie2(['An American in Rome', 'Winter Holidays']))
console.log('---------------')
console.log(getBestMovie2([]))
console.log('---------------')
})
})
実行結果
[ 'An American in Rome', 'Winter Holidays' ]
{ _tag: 'Some', value: 'An American in Rome' }
{ _tag: 'Some', value: 'AN AMERICAN IN ROME' }
{ _tag: 'Some', value: 'Best - AN AMERICAN IN ROME' }
---------------
[]
{ _tag: 'None' }
{ _tag: 'None' }
{ _tag: 'None' }
---------------
[ 'An American in Rome', 'Winter Holidays' ]
{ _tag: 'Some', value: 'An American in Rome' }
{ _tag: 'Some', value: 'AN AMERICAN IN ROME' }
{ _tag: 'Some', value: 'Best - AN AMERICAN IN ROME' }
---------------
[]
{ _tag: 'None' }
{ _tag: 'None' }
{ _tag: 'None' }
---------------
従来のやり方
import { describe, it } from 'vitest'
describe('fp-ts Tutorial', () => {
it('O.map(f)', () => {
const getBestMovie = (titles: ReadonlyArray<string>): string => {
const firstTitle = titles[0]
if (firstTitle === undefined) {
throw Error('Cannot get the best movie.')
}
return `Best 0 ${firstTitle.toLocaleUpperCase()}`
}
console.log(getBestMovie(['An American in Rome', 'Winter Holidays']))
console.log(getBestMovie([]))
})
})
実行結果
Best 0 AN AMERICAN IN ROME
実行時にエラーが出る
※'Cannot get the best movie.'
O.map(f) - O.some(O.none)
import { describe, it } from 'vitest'
import * as O from 'fp-ts/Option'
import { pipe } from 'fp-ts/lib/function'
describe('fp-ts Tutorial', () => {
it('O.map(f) - O.some(O.none)', () => {
const head = <A>(as: ReadonlyArray<A>): O.Option<A> =>
as.length === 0 ? O.none : O.some(as[0])
const inverse = (x: number): O.Option<number> => (x === 0 ? O.none : O.some(1 / x))
const debug_log = <T>(x: T) => {
console.log(x)
return x
}
const inverseHead = (ns: ReadonlyArray<number>) =>
pipe(ns, debug_log, head, debug_log, O.map(inverse))
console.log(inverseHead([0, 2, 4]))
console.log('------------')
console.log(inverseHead([]))
console.log('------------')
})
})
実行結果
[ 0, 2, 4 ]
{ _tag: 'Some', value: 0 }
{ _tag: 'Some', value: { _tag: 'None' } }
------------
[]
{ _tag: 'None' }
{ _tag: 'None' }
------------
O.map(f) - O.flatten
import { describe, it } from 'vitest'
import * as O from 'fp-ts/Option'
import { pipe } from 'fp-ts/lib/function'
describe('fp-ts Tutorial', () => {
it('O.map(f) - O.flatten', () => {
const head = <A>(as: ReadonlyArray<A>): O.Option<A> =>
as.length === 0 ? O.none : O.some(as[0])
const inverse = (x: number): O.Option<number> => (x === 0 ? O.none : O.some(1 / x))
const debug_log = <T>(x: T) => {
console.log(x)
return x
}
const inverseHead = (ns: ReadonlyArray<number>) =>
pipe(ns, debug_log, head, debug_log, O.map(inverse), debug_log, O.flatten)
console.log(inverseHead([0, 2, 4]))
console.log('------------')
console.log(inverseHead([2, 4, 6]))
console.log('------------')
console.log(inverseHead([]))
console.log('------------')
})
})
実行結果
[ 0, 2, 4 ]
{ _tag: 'Some', value: 0 }
{ _tag: 'Some', value: { _tag: 'None' } }
{ _tag: 'None' }
------------
[ 2, 4, 6 ]
{ _tag: 'Some', value: 2 }
{ _tag: 'Some', value: { _tag: 'Some', value: 0.5 } }
{ _tag: 'Some', value: 0.5 }
------------
[]
{ _tag: 'None' }
{ _tag: 'None' }
{ _tag: 'None' }
------------
O.chain(f)
import { describe, it } from 'vitest'
import * as O from 'fp-ts/Option'
import { pipe } from 'fp-ts/lib/function'
describe('fp-ts Tutorial', () => {
it('O.chain(f)', () => {
const head = <A>(as: ReadonlyArray<A>): O.Option<A> =>
as.length === 0 ? O.none : O.some(as[0])
const inverse = (x: number): O.Option<number> => (x === 0 ? O.none : O.some(1 / x))
const debug_log = <T>(x: T) => {
console.log(x)
return x
}
const inverseHead = (ns: ReadonlyArray<number>) =>
pipe(ns, debug_log, head, debug_log, O.chain(inverse))
console.log(inverseHead([0, 2, 4]))
console.log('------------')
console.log(inverseHead([2, 4, 6]))
console.log('------------')
console.log(inverseHead([]))
console.log('------------')
})
})
実行結果
[ 0, 2, 4 ]
{ _tag: 'Some', value: 0 }
{ _tag: 'None' }
------------
[ 2, 4, 6 ]
{ _tag: 'Some', value: 2 }
{ _tag: 'Some', value: 0.5 }
------------
[]
{ _tag: 'None' }
{ _tag: 'None' }
------------
Chapter 2.2: Option fromPredicate
O.fromPredicate(predicate) - 1
isEven(x) = \left\{
\begin{array}{ll}
true & (x\bmod 2 = 0) \\
false & (x\bmod 2 \neq 0)
\end{array}
\right.
import { describe, it } from 'vitest'
import * as O from 'fp-ts/Option'
describe('fp-ts Tutorial', () => {
it('O.fromPredicate(predicate) - 1', () => {
const isEven = (a: number) => a % 2 === 0
const getEven = O.fromPredicate(isEven)
console.log(getEven(4))
console.log(getEven(5))
})
})
実行結果
{ _tag: 'Some', value: 4 }
{ _tag: 'None' }
O.fromPredicate(predicate) - 2
isDiscountValid(x) = \left\{
\begin{array}{ll}
true & (x.expired \neq true) \\
false & (x.expired = true)
\end{array}
\right.
import { describe, it } from 'vitest'
import * as O from 'fp-ts/Option'
import { pipe } from 'fp-ts/lib/function'
describe('fp-ts Tutorial', () => {
it('O.fromPredicate(predicate) - 2', () => {
type Discount = Readonly<{
percentage: number
expired: boolean
}>
const isDiscountValid = (discount: Discount) => !discount.expired
const debug_log = <T>(x: T) => {
console.log(x)
return x
}
const getDiscountText = (discount: Discount): O.Option<string> =>
pipe(
discount,
debug_log,
O.fromPredicate(isDiscountValid),
debug_log,
O.map(({ percentage }) => `${percentage}% DISCOUNT!`)
)
console.log(getDiscountText({ percentage: 10, expired: false }))
console.log('---------------')
console.log(getDiscountText({ percentage: 20, expired: true }))
console.log('---------------')
})
})
実行結果
{ percentage: 10, expired: false }
{ _tag: 'Some', value: { percentage: 10, expired: false } }
{ _tag: 'Some', value: '10% DISCOUNT!' }
---------------
{ percentage: 20, expired: true }
{ _tag: 'None' }
{ _tag: 'None' }
---------------
O.fromPredicate(refinement)
isCircle(x) = \left\{
\begin{array}{ll}
true & (x.type = Circle) \\
false & (x.type \neq Circle)
\end{array}
\right.
import { describe, it } from 'vitest'
import * as O from 'fp-ts/Option'
describe('fp-ts Tutorial', () => {
it('O.fromPredicate(refinement)', () => {
interface Circle {
type: 'Circle'
radius: number
}
interface Square {
type: 'Square'
side: number
}
type Shape = Circle | Square
const isCircle = (s: Shape): s is Circle => s.type === 'Circle'
const getCircle = O.fromPredicate(isCircle)
console.log(getCircle({ type: 'Circle', radius: 3 }))
console.log(getCircle({ type: 'Square', side: 4 }))
})
})
実行結果
{ _tag: 'Some', value: { type: 'Circle', radius: 3 } }
{ _tag: 'None' }
Chapter 2.3: Option error handling
getMovieAwardHighlight
import { describe, it } from 'vitest'
import * as O from 'fp-ts/Option'
import { pipe } from 'fp-ts/lib/function'
describe('fp-ts Tutorial', () => {
it('O.alt(f)', () => {
interface Movie {
title: string
releaseYear: number
ratingPosition: number
award?: string
}
const debug_log = <T>(x: T) => {
console.log(x)
return x
}
const getMovieAwardHighlight = (movie: Movie): O.Option<string> =>
pipe(
movie.award,
debug_log,
O.fromNullable,
debug_log,
O.map((award) => `Awarded with: ${award}`)
)
const movie1: Movie = {
title: 'The Kingdom of Monads',
releaseYear: 2023,
ratingPosition: 1,
award: 'Oscar'
}
const movie2: Movie = {
title: 'Natural Transformations',
releaseYear: 2023,
ratingPosition: 3
}
const movie3: Movie = {
title: 'Fun with for loops',
releaseYear: 2023,
ratingPosition: 74
}
console.log(getMovieAwardHighlight(movie1))
console.log('---------------')
console.log(getMovieAwardHighlight(movie2))
console.log('---------------')
console.log(getMovieAwardHighlight(movie3))
console.log('---------------')
})
})
実行結果
Oscar
{ _tag: 'Some', value: 'Oscar' }
{ _tag: 'Some', value: 'Awarded with: Oscar' }
---------------
undefined
{ _tag: 'None' }
{ _tag: 'None' }
---------------
undefined
{ _tag: 'None' }
{ _tag: 'None' }
---------------
getMovieTop10Highlight
import { describe, it } from 'vitest'
import * as O from 'fp-ts/Option'
import { pipe } from 'fp-ts/lib/function'
describe('fp-ts Tutorial', () => {
it('O.alt(f)', () => {
interface Movie {
title: string
releaseYear: number
ratingPosition: number
award?: string
}
const debug_log = <T>(x: T) => {
console.log(x)
return x
}
const getMovieTop10Highlight = (movie: Movie): O.Option<string> =>
pipe(
movie,
debug_log,
O.fromPredicate(({ ratingPosition }) => ratingPosition <= 10),
debug_log,
O.map(({ ratingPosition }) => `In TOP 10 at position: ${ratingPosition}`)
)
const movie1: Movie = {
title: 'The Kingdom of Monads',
releaseYear: 2023,
ratingPosition: 1,
award: 'Oscar'
}
const movie2: Movie = {
title: 'Natural Transformations',
releaseYear: 2023,
ratingPosition: 3
}
const movie3: Movie = {
title: 'Fun with for loops',
releaseYear: 2023,
ratingPosition: 74
}
console.log(getMovieTop10Highlight(movie1))
console.log('---------------')
console.log(getMovieTop10Highlight(movie2))
console.log('---------------')
console.log(getMovieTop10Highlight(movie3))
console.log('---------------')
})
})
実行結果
{
title: 'The Kingdom of Monads',
releaseYear: 2023,
ratingPosition: 1,
award: 'Oscar'
}
{
_tag: 'Some',
value: {
title: 'The Kingdom of Monads',
releaseYear: 2023,
ratingPosition: 1,
award: 'Oscar'
}
}
{ _tag: 'Some', value: 'In TOP 10 at position: 1' }
---------------
{
title: 'Natural Transformations',
releaseYear: 2023,
ratingPosition: 3
}
{
_tag: 'Some',
value: {
title: 'Natural Transformations',
releaseYear: 2023,
ratingPosition: 3
}
}
{ _tag: 'Some', value: 'In TOP 10 at position: 3' }
---------------
{ title: 'Fun with for loops', releaseYear: 2023, ratingPosition: 74 }
{ _tag: 'None' }
{ _tag: 'None' }
---------------
O.alt(f)
import { describe, it } from 'vitest'
import * as O from 'fp-ts/Option'
import { pipe } from 'fp-ts/lib/function'
describe('fp-ts Tutorial', () => {
it('O.alt(f)', () => {
interface Movie {
title: string
releaseYear: number
ratingPosition: number
award?: string
}
const debug_log = <T>(x: T) => {
console.log(x)
return x
}
const getMovieAwardHighlight = (movie: Movie): O.Option<string> =>
pipe(
movie.award,
// debug_log,
O.fromNullable,
// debug_log,
O.map((award) => `Awarded with: ${award}`)
)
const getMovieTop10Highlight = (movie: Movie): O.Option<string> =>
pipe(
movie,
// debug_log,
O.fromPredicate(({ ratingPosition }) => ratingPosition <= 10),
// debug_log,
O.map(({ ratingPosition }) => `In TOP 10 at position: ${ratingPosition}`)
)
const getMovieHighlight = (movie: Movie): string =>
pipe(
movie,
debug_log,
getMovieAwardHighlight,
debug_log,
O.alt(() => getMovieTop10Highlight(movie)),
debug_log,
O.getOrElse(() => `Released in ${movie.releaseYear}`)
)
const movie1: Movie = {
title: 'The Kingdom of Monads',
releaseYear: 2023,
ratingPosition: 1,
award: 'Oscar'
}
const movie2: Movie = {
title: 'Natural Transformations',
releaseYear: 2023,
ratingPosition: 3
}
const movie3: Movie = {
title: 'Fun with for loops',
releaseYear: 2023,
ratingPosition: 74
}
console.log(getMovieHighlight(movie1))
console.log('---------------')
console.log(getMovieHighlight(movie2))
console.log('---------------')
console.log(getMovieHighlight(movie3))
console.log('---------------')
})
})
実行結果
{
title: 'The Kingdom of Monads',
releaseYear: 2023,
ratingPosition: 1,
award: 'Oscar'
}
{ _tag: 'Some', value: 'Awarded with: Oscar' }
{ _tag: 'Some', value: 'Awarded with: Oscar' }
Awarded with: Oscar
---------------
{
title: 'Natural Transformations',
releaseYear: 2023,
ratingPosition: 3
}
{ _tag: 'None' }
{ _tag: 'Some', value: 'In TOP 10 at position: 3' }
In TOP 10 at position: 3
---------------
O.altW(f) - W means Widen
赤い背景のところでエラーが出る
import { describe, it } from 'vitest'
import * as O from 'fp-ts/Option'
import { pipe } from 'fp-ts/lib/function'
describe('fp-ts Tutorial', () => {
it('O.altW(f)', () => {
const f = (a: O.Option<number>) =>
pipe(
- a,
O.alt(() => O.some('invalid'))
)
console.log(f(O.of(3)))
console.log(f(O.none))
})
})
実行結果
{ _tag: 'Some', value: 3 }
{ _tag: 'Some', value: 'invalid' }
※VSCodeなどでエラー表示されるが、実行は可能
※Argument of type 'Option' is not assignable to parameter of type 'Option'.
O.altW ならエラー表示なし
import { describe, it } from 'vitest'
import * as O from 'fp-ts/Option'
import { pipe } from 'fp-ts/lib/function'
describe('fp-ts Tutorial', () => {
it('O.altW(f)', () => {
const f = (a: O.Option<number>) =>
pipe(
a,
O.altW(() => O.some('invalid'))
)
console.log(f(O.of(3)))
console.log(f(O.none))
})
})
実行結果
{ _tag: 'Some', value: 3 }
{ _tag: 'Some', value: 'invalid' }