Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Boxed: bringing algebraic types to TypeScript
Search
Matthias Le Brun
March 27, 2024
Technology
190
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Boxed: bringing algebraic types to TypeScript
Matthias Le Brun
March 27, 2024
More Decks by Matthias Le Brun
See All by Matthias Le Brun
GraphQL, Pothos & SQLite: a perfect match
bloodyowl
0
120
(why the hell did I) build a GraphQL client for the browser
bloodyowl
0
160
leveraging (algebraic data) types to make your UI rock @ jsheroes
bloodyowl
0
340
Leveraging (algebraic data) types to make your UI rock solid
bloodyowl
0
520
La drôle d'histoire de JavaScript
bloodyowl
0
410
Healthy Code Collaboration
bloodyowl
0
370
Simplify your UI management with (algebraic data) types
bloodyowl
0
860
Simplify your UI management with (algebraic data) types
bloodyowl
1
590
Migrating a large Reason+React codebase to hooks
bloodyowl
0
620
Other Decks in Technology
See All in Technology
【CEDEC2026】『Relink』を拡張せよ - 『GRANBLUE FANTASY: Relink - Endless Ragnarok』の開発速度と品質を守るCI運用
cygames
PRO
0
140
Forza Horizon 6 のテレメトリ機能で 自動運転に使えそうな学習データを集める話
henjin0
0
140
もう一度考える SRE チームの作り方・育て方 / Rethinking SRE #1: Building and Growing SRE Teams
rrreeeyyy
6
1k
【Google Cloud Next Tokyo'26】Gemini Enterprise と Oracle AI Database で実現する、業務データ活用を実現する AI エージェント実装
shisyu_gaku
0
230
初めてのGitHub Actions / GitHub Actions at First
tooppoo
0
150
Bill One 開発エンジニア 紹介資料
sansan33
PRO
7
19k
オートロックマンションなのに、各部屋は施錠なし!? 攻撃者が組織内ネットワークで大暴れする理由 / The Front Door Is Locked, but the Rooms Are Wide Open: Why Attackers Move Freely Inside Enterprise Networks
nttcom
1
1.6k
変化の早いClaude Codeを 書籍に落とし込む
oikon48
7
1.3k
【CEDEC2026】グラフィックスエンジニアのためのニューラルシェーディング入門
cygames
PRO
0
120
QAエンジニア起点で進める、SmartHRにおける信頼性向上について
kaomi_wombat
1
120
つくって納得、つかって実感! 大規模言語モデルことはじめ ver2.0
recruitengineers
PRO
3
1.1k
修正PRを食べてレビュースキルが賢くなる:Claude Codeによる自己改善サイクル
yuyaumetsu
5
1.4k
Featured
See All Featured
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
890
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
64
56k
Automating Front-end Workflow
addyosmani
1370
210k
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.5k
Crafting Experiences
bethany
1
240
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
270
Darren the Foodie - Storyboard
khoart
PRO
3
3.5k
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
680
Technical Leadership for Architectural Decision Making
baasie
3
470
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.5k
Prompt Engineering for Job Search
mfonobong
0
400
Transcript
Boxed
Matthias Le Brun @bloodyowl lead engineering manager chief shitpost office
the easiest way to provide banking features (accounts, payments, cards…) we're hiring! @
None
None
None
None
PREVIOUSLY ON Matthias tries to convert people to FP
Algebraic Data Types yay
type State = { data?: Data; error?: Error; };
type State = { data?: Data; error?: Error; }; type
Result<Data> = | Ok<Data> | Error<Error>; error data ERROR NULL NULL DATA NULL NULL ERROR DATA
{ data: null; error: null; };
type Result<Data> = | Ok<Data> | Error<Error>;
type State = { data?: Data; error?: Error; }; type
Result<Data> = | Ok<Data> | Error<Error>; state ERROR DATA
API response API response
API response API response
type State = { data?: Data; error?: Error; }; type
Result<Data> = | Ok<Data> | Error<Error>; 2 2 1 1 4 2 x = + =
Algebra it's just basic math™
+ x
quiz 157 x 8341 = ?
quiz 999 + 1 = ?
union types
monads functors
functor
monad
[1, 2, 3].map(x => x * 2) // [2, 4,
6] [1, 2, 3].flatMap(x => [x, x * 2]) // [1, 2, 2, 4, 3, 6]
map: <A, B>(T<A>, (a: A) => B) => T<B>: flatMap:
<A, B>(T<A>, (a: A) => T<B>) => T<B>;
None
null & undefined are bad
errors aren't always exceptions
promises were made the wrong way in JS
promises were made the wrong way in JS
promises were made the wrong way in JS
promises were made the wrong way in JS
THAT WAS Matthias tries to convert people to FP NOW
LET'S TALK ABOUT BOXED
✨ new job ✨ 2022
«we use TypeScript»
None
let's look at the ecosystem™
fp-ts
pipe( token, TaskEither.bindW("user", getTokenFromUser), TaskEither.bindW("project", getProject), TaskEither.chainW(getMembership), ) no autocomplete
on current value
pipe( token, TaskEither.bindW("user", getTokenFromUser), TaskEither.bindW("project", getProject), TaskEither.chainW(getMembership), x => {}
) need to inspect argument for type
pipe( token, TaskEither.bindW("user", getTokenFromUser), TaskEither.bindW("project", getProject), TaskEither.chainW(getMembership), x => {}
) need to inspect argument for type not a good DX
export declare const chainFirstTaskK: <A, B>(f: (a: A) = >
T.Task<B>) = > <E>(first: TaskEither<E, A>) = > TaskEither<E, A> ah just what I was looking for
we've looked at the ecosystem™
«let's try to make these types work with a good
DX in a structurally typed language» — me, allegedly drunk
structural typing
class Some<A> {} class None {} const value: Some<string> =
new None();
what we need → good DX → interop with ts-pattern
→ fast
what we needed → chaining API → autocomplete → less
imports
1st iteration: naive wanted the types to be opaque but
safe
1st iteration: naive discriminator in TS (aka poor man's nominal
types)
1st iteration: naive and we're storing the state in the
class instance
None
1st iteration: naive wanted the types to be opaque but
safe
1st iteration: naive wanted the types to be opaque but
safe
2nd iteration: anger
2nd iteration: anger
2nd iteration: anger
2nd iteration: anger
3rd iteration: make it fast
initial release
initial release
type Option<A> = Some<A> | None;
type Result<A, E> = Ok<A> | Error<E>;
type AsyncData<A> = | NotAsked | Loading | Done<A>;
Future<A>; better promises™ cancellable monadic leaves error state to Result
const parsed = input != null ? parseInput(input) : undefined;
const transformed = parsed != null ? transform(parsed) : undefined; const printed = transformed != null ? print(transformed) : undefined; const value = printed != null ? prettify(printed) : "fallback"; input .map(parseInput) .flatMap(transform) .map(print) .map(prettify) .getWithDefault("fallback");
user-testing
None
insights people need human-written docs → we doubled down on
examples & added search
insights don't try to replicate another language → give good
defaults for TS
Result< Data, ServerError > Result< A, ServerError | FinalizeError >
insights people are familiar with just a few data types
→ reduce confusion
insights people can be docs-first or type-first → experience needs
to be good for both
insights readability matters → chaining API was the way to
go
insights mapping on existing JS knowledge helps → if it
exists, name it the same way
insights pipe() syntax had impact on the runtime → expressiveness
is important
4th iteration implement the feedback rename some methods update some
defaults
5th iteration: what the actual fu
5th iteration: what the actual fu
recently fix the errors
recently improved perf by 2x to 10x
recently improved perf by 2x to 10x blazing fast certi
fi ed™ ⚡
Boxed → github.com/swan-io/boxed → swan-io.github.io/boxed
None
$ yarn add @swan-io/boxed
Matthias Le Brun @bloodyowl we're still hiring thank you! 🙏