Railway Oriented TypeScript Robin Pokorny
A presentation at Heapcon 2022 in November 2022 in Belgrade, Serbia by Robin Pokorny
Railway Oriented TypeScript Robin Pokorny
Heapcon Typescript Functional Programming Heapcon 2022 is over, Welcome to the slides! If you’re reading this my talk is over. I welcome any feedback, questions, These are the slides that you can or comments! look at if you’d like to refresh your memory. So glad you are here. Let’s keep in touch. You can nd all my social pro les as well as my Of course, static slides are not going email on my homepage: to replace being there, so please https://robinpokorny.com. keep that in mind. During my talk, I do some live coding. The result of that is here: https://gist.github.com/robinpokorny/ fi fi 7bcde83da63463979e4916aa992192e4 Happy exploring! Robin
Example A Simple Response To A Request Happy-Path Code What if data is not valid? const action = (req, res) 1 validate(req); { const newData = updateDB(req.body); 2 log(newData); 3 return res.send(newData); }; > 3 = What if log fails? What if the DB is unreachable?
Functional Programming Don’t leave! 4
Monad Semigroup Category Sum type Functor Foldable
Erlang Haskell I ❤ FP Closure
Next 30 minutes 1 2 3 Show TypeScript Code Don’t tell But, why? Yes, really 7
Scott Wlaschin Railway Oriented Programming 8
””“”” “”“”“”“”“” ” “”“”“”“” “”“”“”“” “”“”“”“”” “” “”“”“”” “” “”“”“”“”“”“” “” “”” “”” “”“”” “”“”” “”“”“”“”“”“”“” “”“”“” “”“”“”“”“”“”“”” “”“”“”“”“”“”“” “”“”“”“”” “”“”“”“”” “”“”“” “”“”“”“”“”“”“” “”“”“”“”“”“”“”” “”“”“”“”“” “”” “”“”” “”“”“” “”“”“”“” ” “” “” ” “”“”” “”“”” ” “”“”“”“”“”” “”“”” “”“” ” “”“”“”“” “”“”“”“”“”” ” “”“”“”“” “”” “”“”“” “”” “”“”“”“”” “”” “” “”“”“”” “”“”“”” “”“” “”“”“”“”” “”“”” “”“”“”“”“” “”“”” “”“”“” “”” “”“” “”“”“” “”“”“”” “”“”“”“”“”“”“”” “”“”“” “” ” “”“”“”“”“”“”“”“”“” ” “”“”” “”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”” “”“” “” ” “”“”“”“”“”“”“”” “” “”“”“”“” “”“”” “”“” “”” “”“”“”“”“”“”” “” ” “”“”“”“”“”“”“” “” “”“”“”“”“”” “”” “”“”“”“”“” ” “”“”“”“”“”“”“”“”“”“”” “”“”“” “”“”“”“”“”“”“”” “”” ” “”“” ” “”“”“”“”“”“”“”“”“”“”“”“”“” “”“”” “”“” “”“”“”“”“”“”” ” “” “”“”“” “”” “” “” “” “” “”“”“” ” “”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” ” “”“”” “”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”” “”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”” “” “”“”“”“”“”“”“”” “”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”” “” “”“”“”“”“”“”“”” “”“”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”” “” “”“”“”“”“”“”“”” “”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”” “” “”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“” “”“”“”“”“”” “”“” “” ” “”“”“”“”“”” “” “”“”“”” “”“”“”“”“”” “”” “”“”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“” “” “”“”“”” “”“”“”“”“”“”” “” “” 9
🍏 🍌 Function Apple -> Banana 10
🍏 🍌 🍌 🍏 🍓 🍓 11
const action = (req, res) validate(req); { const newData = updateDB(req.body); log(newData); return res.send(newData); const action = (req, res) { const { value, error } = validate(req); if (error null) { return res .status(400) .send(“Invalid request”); } 💥 let newData; }; try { newData = updateDB(req.body); } catch (e) { log(e) return res .status(500) .send(“Something went wrong 🤷”); } 💥 💥 try { log(newData); } catch (e) { Just log the logging error log(e) } return res.send(newData);
= ! / / }; 12
””“”” “”“”“”“”“” ” “”“”“”“” “”“”“”“” “”“”“”“”” “” “”“”“”” “” “”“”“”“”“”“” “” “”” “”” “”“”” “”“”” “”“”“”“”“”“”“” “”“”“” “”“”“”“”“”“”“”” “”“”“”“”“”“”“” “”“”“”“”” “”“”“”“”” “”“”“” “”“”“”“”“”“”“” “”“”“”“”“”“”“”” “”“”“”“”“” “”” “”“”” “”“”“” “”“”“”“” ” “” “” ” “”“”” “”“”” ” “”“”“”“”“”” “”“”” “”“” ” “”“”“”“” “”“”“”“”“”” ” “”“”“”“” “”” “”“”“” “”” “”“”“”“”” “”” “” “”“”“”” “”“”“”” “”“” “”“”“”“”” “”“”” “”“”“”“”“” “”“”” “”“”“” “”” “”“” “”“”“” “”“”“”” “”“”“”“”“”“”“”” “”“”“” “” ” “”“”“”“”“”“”“”“”“” ” “”“”” “”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”” “”“” “” ” “”“”“”“”“”“”“”” “” “”“”“”“” “”“”” “”“” “”” “”“”“”“”“”“”” “” ” “”“”“”“”“”“”“” “” “”“”“”“”“”” “”” “”“”“”“”“” ” “”“”“”“”“”“”“”“”“”“”” “”“”“” “”“”“”“”“”“”“”” “”” ” “”“” ” “”“”“”“”“”“”“”“”“”“”“”“”“” “”“”” “”“” “”“”“”“”“”“”” ” “” “”“”“” “”” “” “” “” “” “”“”“” ” “”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” ” “”“”” “”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”” “”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”” “” “”“”“”“”“”“”“”” “”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”” “” “”“”“”“”“”“”“”” “”“”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”” “” “”“”“”“”“”“”“”” “”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”” “” “”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“” “”“”“”“”“”” “”“” “” ” “”“”“”“”“”” “” “”“”“”” “”“”“”“”“”” “”” “”“”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“” “” “”“”“”” “”“”“”“”“”“”” “” “” 13
Input Success Failure 15
Success DB g Lo e te da up at id al V Failure 16
Demo “”“”“” ” “”“”“” “”“”” “”“”“”“”“”“”“”“”“” “”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “!”“”“”“”“”“”“”“”“”“”“”” “” ” “”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“” “”“”“”“” “” “”“”“”” “”“”“”“”“” “”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “”“”“”“” “”“”“”“”“”“”“”“” “”“”“”“” “” “”“”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”” “” “”“”“”“”“”“”“”“”“”“”“”” “” “”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”” “” “”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“” “” “”“”“”” “” “” |””“”“”“” “”“”“” ” “”“”“” “”“”” “”“”“”“”“”“”“”“”“” “”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “!”“”“”“”“”“”“”“”“”“”“”” “” ” “”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“” “”“”“”“” “” “”“”“”” “”“”“”“”“” “”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “”“”“”“” “”“”“”“”“”“”“”“” “”“”“”“” “” “”“”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”” “” “”“”“”“”“”“”“”“”“”“”“”” “” “”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”” “” “”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“” “” “”“”“”” “” |””“”“”“”“”“”“”“” |””“”“”“”“”“”” |””“”“”“” | |””“”“”“” | |””“”“”“”“”“”“”“”“”“” | |””“”“”“”“”“”“”“”” | |””“”“”“”“”“”“”” |””“”“”“”“”“”” |””“”“”“” |””“”“”“”“”” |””“” | |””“”“”“”“” | |””“”“”“”“” |””“”“”“”“” |””“”“”“”“”“”” |””“”” | |””“”“”“”” | |””“”“”“”“”“” | |””“”“”“” “” 17
YAGNI…? You Ain’t Gonna Need It… ? 18
Typescript Self-Documenting Code Exhaustive Failure Checking Composing Can Be Tricky 19
Success DB g Lo e te da up at id al V Failure 20
Input Success Also input? Failure 21
Bypass 22
Demo “”“”“” ” “”“”“” “”“”” “”“”“”“”“”“”“”“”“” “”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “!”“”“”“”“”“”“”“”“”“”“”” “” ” “”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“” “”“”“”“” “” “”“”“”” “”“”“”“”“” “”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “”“”“”“” “”“”“”“”“”“”“”“” “”“”“”“” “” “”“”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”” “” “”“”“”“”“”“”“”“”“”“”“”” “” “”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”” “” “”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“” “” “”“”“”” “” “” |””“”“”“” “”“”“” ” “”“”“” “”“”” “”“”“”“”“”“”“”“”“” “”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “!”“”“”“”“”“”“”“”“”“”“”” “” ” “”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“” “”“”“”“” “” “”“”“”” “”“”“”“”“” “”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “”“”“”“” “”“”“”“”“”“”“”“” “”“”“”“” “” “”“”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”” “” “”“”“”“”“”“”“”“”“”“”“”” “” “”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”” “” “”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“” “” “”“”“”” “” |””“”“”“”“”“”“”“” |””“”“”“”“”“”” |””“”“”“” | |””“”“”“” | |””“”“”“”“”“”“”“”“”“” | |””“”“”“”“”“”“”“”” | |””“”“”“”“”“”“”” |””“”“”“”“”“”” |””“”“”“” |””“”“”“”“”” |””“” | |””“”“”“”“” | |””“”“”“”“” |””“”“”“”“” |””“”“”“”“”“”” |””“”” | |””“”“”“”” | |””“”“”“”“”“” | |””“”“”“” “” 23
Promise.resolve() YAGNI…? You Ain’t Gonna Need It… ? 24
Promises Limited API 25
Promises API Methods Combinators Promise#then Promise.race Promise#catch Promise.allSettled Promise# nally Promise.all Promise.any fi 26
Promises Limited API Domain ✖ Panic 27
Errors Domain Expected Panic Unhandleable t s u ha x E o N s k c e h c e v i INVALID INPUT DATA OUT OF MEMORY EXTERNAL SYSTEM UNREACHABLE DIVIDE BY ZERO 28
Demo “”“”“” ” “”“”“” “”“”” “”“”“”“”“”“”“”“”“” “”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “!”“”“”“”“”“”“”“”“”“”“”” “” ” “”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“” “”“”“”“” “” “”“”“”” “”“”“”“”“” “”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “”“”“”“” “”“”“”“”“”“”“”“” “”“”“”“” “” “”“”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”” “” “”“”“”“”“”“”“”“”“”“”“”” “” “”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”” “” “”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“” “” “”“”“”” “” “” |””“”“”“” “”“”“” ” “”“”“” “”“”” “”“”“”“”“”“”“”“”“” “”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “!”“”“”“”“”“”“”“”“”“”“”” “” ” “”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“” “”“”“”“” “” “”“”“”” “”“”“”“”“” “”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “”“”“”“” “”“”“”“”“”“”“”“” “”“”“”“” “” “”“”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”” “” “”“”“”“”“”“”“”“”“”“”“”” “” “”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”” “” “”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“” “” “”“”“”” “” |””“”“”“”“”“”“”“” |””“”“”“”“”“”” |””“”“”“” | |””“”“”“” | |””“”“”“”“”“”“”“”“”“” | |””“”“”“”“”“”“”“”” | |””“”“”“”“”“”“”” |””“”“”“”“”“”” |””“”“”“” |””“”“”“”“”” |””“” | |””“”“”“”“” | |””“”“”“”“” |””“”“”“”“” |””“”“”“”“”“”” |””“”” | |””“”“”“”” | |””“”“”“”“”“” | |””“”“”“” “” 29
Fp-ts https://github.com/gcanti/fp-ts 30
””“”” “”“”“”“”“” ” “”“”“”“” “”“”“”“” “”“”“”“”” “” “”“”“”” “” “”“”“”“”“”“” “” “”” “”” “”“”” “”“”” “”“”“”“”“”“”“” “”“”“” “”“”“”“”“”“”“”” “”“”“”“”“”“”“” “”“”“”“”” “”“”“”“”” “”“”“” “”“”“”“”“”“”“” “”“”“”“”“”“”“”” “”“”“”“”“” “”” Left “”“”” “”“”“” “”“”“”“” ” “” “” ” “”“”” “”“”” ” “”“”“”“”“”” “”“”” “”“” ” “”“”“”“” “”“”“”“”“”” ” “”“”“”“” “”” “”“”“” “”” “”“”“”“”” “”” “” “”“”“”” “”“”“”” “”“” “”“”“”“”” “”“”” “”“”“”“”“” “”“”” “”“”“” “”” “”“” “”“”“” “”“”“”” “”“”“”“”“”“”“”” “”“”“” “” ” “”“”“”“”“”“”“”“”“” ” “”“”” “”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”” “”“” “” ” “”“”“”“”“”“”“”” “” “”“”“”“” “”“”” “”“” “”” “”“”“”“”“”“”” “” ” “”“”“”“”“”“”“” “” “”“”“”“”“”” “”” “”“”“”“”“” ” “”“”“”“”“”“”“”“”“”“”” “”“”“” “”“”“”“”“”“”“”” “”” ” “”“” ” “”“”“”“”“”“”“”“”“”“”“”“”“” “”“”” “”“” “”“”“”“”“”“”” ” “” “”“”“” “”” “” “” “” “” “”“”“” ” “”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”” ” “”“”” “”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”” “”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“”” “” “”“”“”“”“”“”“”” “”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”” “” “”“”“”“”“”“”“”” “”“”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”” “” “”“”“”“”“”“”“”” “”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”” “” “”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“” “”“”“”“”“”” “”“” “” ” “”“”“”“”“”” “” “”“”“”” “”“”“”“”“”” “”” “”“”“”“”“”“”“”“”“”“”” “”“”“”“”“”“”“”“”“”“”“”“”“” “” “”“”“”” “”“”“”“”“”“”” “” “” Right Either<S, T> = | Left<S> | Right<T> Result<T, S> = | Success<T> | Failure<S> Failure Success 31
32
Aleksandr Morozov @morozov_dev When your code works, but you have no idea how 2:05 AM · Nov 3, 2022 33
34
“You Have To Master A New Skill, But You’re Avoiding It Because You Know You’ll Be Bad At It When You First Do It.”
Railway Oriented TypeScript @robinpokorny