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
TypeScript サーバーサイドエンジニアが関数型から学 ぶべき 3 つのアイディア
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
majimaccho
May 27, 2025
740
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
TypeScript サーバーサイドエンジニアが関数型から学 ぶべき 3 つのアイディア
majimaccho
May 27, 2025
More Decks by majimaccho
See All by majimaccho
Result 型、自前で書くか、ライブラリ使うか
majimaccho
5
990
graphql-rdb-mismatch
majimaccho
0
65
tblsはいいぞ(第44回 PostgreSQLアンカンファレンス@オンライン)
majimaccho
0
350
Featured
See All Featured
Into the Great Unknown - MozCon
thekraken
41
2.6k
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
A designer walks into a library…
pauljervisheath
211
24k
Facilitating Awesome Meetings
lara
57
7k
Docker and Python
trallard
47
3.9k
Abbi's Birthday
coloredviolet
3
8.2k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1.2k
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.3k
Building Adaptive Systems
keathley
44
3.1k
ラッコキーワード サービス紹介資料
rakko
1
3.7M
The Language of Interfaces
destraynor
162
27k
Transcript
TypeScript サーバーサイドエンジニアが関数型から学 ぶべき 3 つのアイディア @TSKaigi 2025 After Night 1
自己紹介 名前:majimaccho お仕事: @caddi 職種: Web App Engineer X: @majimaccho_
2
TSKaigi お疲れ様でした! 3
4
落選したプロポーザールに書いた もっと話したかったことを話します 5
TSKaigi 2024・2025 に参加して思いました 6
7
みんな関数型好き〜〜〜(私も好き) 8
しかし 9
TypeScript は関数型言語ではありません 10
TypeScript は関数型言語ではない React をはじめフロントエンドでは関数型言語のプラクティスが取り入れられてい る 型の表現力の高さは TypeScript の美点で、現代の関数型言語のプラクティスと相性 が良い 一方で、現代の関数型言語に当たり前にある機能が
TypeScript にはない。そのた め、素の TypeScript に関数型言語のプラクティスを全て取り入れることはできない。 11
何を取り入れるかのベスプラはまだ定まっていない そもそも関数型を取り入れること自体が ベストプラクティスなのかも合意されていないと思われる 12
今回は TypeScript の言語仕様に相性が良いものに限って 取り入れる価値のあるアイディアを紹介します 13
TypeScript サーバーサイドエンジニアが関数型から学ぶべき 3 つ のアイディア Make illegal states unpresentable(不正な状態を定義できないようにする) Parse,
don’t validate (バリデーションするな、パースせよ) Result 型 14
Make illegal states unrepresentable (不正な状態を定義できないようにする) 書籍、関数型ドメインモデリングで有名になった考 え方 内部状態の組み合わせを隠蔽しない クラスではロジック+テストでこれを表現するが 関数型のアプローチでは代数的データ型で表現する
15
Make illegal states unrepresentable 連絡先(ContactInfo)はメールアドレスか郵送先の どちらか、または両方を持つことができる どちらも持たない状態は許容されないというルールを型で表現する type EmailOnlyContactInfo =
{ type: "EmailOnly"; email: EmailContactInfo }; type PostalOnlyContactInfo = { type: "PostalOnly"; postal: PostalContactInfo }; type EmailAndPostalContactInfo = { type: "EmailAndPostal"; email: EmailContactInfo; postal: PostalContactInfo; }; type ContactInfo = | EmailOnlyContactInfo | PostalOnlyContactInfo | EmailAndPostalContactInfo; 16
Make illegal states unrepresentable は AI に優しい (mizchi さんの発表から) 17
振る舞いについても型で表現する メールを送信する関数は、メールアドレスが存在する場合にのみ呼び出せる ContactInfo の変更時にも型で影響の有無が明示される const sendEmail = async ( //
PostalOnlyContactInfoは許容しない contact: EmailOnlyContactInfo | EmailAndPostalContactInfo ): Promise<EmailSendResult> => { // ここでEmailが存在することを型で保証されているので // 検証ロジックは不要 }; 18
Parse, don’t validate (バリデーションするな、パースせよ) 外界からの信頼できない入力は可能な限り外側の層で信頼可能な値に Parse する Unvalidated(未検証)と Validated(検証済)明確に型レベルで区別する Always
Valid Domain Model / セキュアバイデザインでも類似した考え方がある 不正な状態は存在してはいけないとすることで後続コードは全て入力値の正しさ を信じることができる 19
Parse, don’t validate ではない例 const validateEmail = (emailStr: string): boolean
=> { // 無効なメールアドレスであれば false を返す // 有効なメールアドレスであれば true を返す }; const sendEmail = async (emailStr: string) => { if (!validateEmail(emailStr)) { throw new InvalidEmailAddressError(emailStr); } // このままでは EmailService.sendはemailStr が不正な値である可能性がある await EmailService.send(emailStr); }; 20
Parse, don’t validate の例 const parseEmail = ( unvalidatedEmail: string
): | { isOk: true; value: ValidatedEmail } | { isOk: false; error: InvalidEmailFormatError } => { // 有効なメールアドレスであればtrueではなく // { isOk: true, value: ValidatedEmail } を返す // 無効なメールアドレスであれば // { isOk: false, error: InvalidEmailFormatError } を返す }; const sendEmail = async (unvalidatedEmail: string) => { const parseResult = parseEmail(unvalidatedEmail); if (!parseResult.isOk) { return parseResult.error; } // EmailService.sendは引数の値を信用できるため再度検証する必要はない await EmailService.send(parseResult.value); }; 21
宣伝:翻訳したよ 22
Result 型 TS の try-catch はエラーを unknown にする どの関数が throw
するのかインターフェースから理解不能 23
さっきの Parse, don’t validate の例は Result 型を返している const parseEmail =
( unvalidatedEmail: string ): | { isOk: true; value: ValidatedEmail } | { isOk: false; error: InvalidEmailFormatError } => {...}; const sendEmail = async (unvalidatedEmail: string) => { const parseResult = parseEmail(unvalidatedEmail); if (!parseResult.isOk) { return parseResult.error; } await EmailService.send(parseResult.value); }; 24
型定義から起こりうるエラーが明示されている const parseEmail = ( unvalidatedEmail: string ): | {
isOk: true; value: ValidatedEmail } | { isOk: false; error: InvalidEmailFormatError } => { // 無効なメールアドレスであれば // { isOk: false, error: InvalidEmailFormatError } を返す // 有効なメールアドレスであれば // { isOk: true, value: ValidatedEmail } を返す }; 25
呼び出し時のエラーハンドリングも改善される 起こりうるエラーが明示的なのでエラー型ごとに個別に対処できる Result 型 const sendEmail = async (unvalidatedEmail: string)
=> { const parseResult = parseEmail(unvalidatedEmail); if (!parseResult.isOk) { // isOkがfalseの場合が起こりうるので処理が必要であることが明示的 return parseResult.error; } await EmailService.send(parseResult.value); }; 26
汎用 Result 型を定義する type Result<T, E> = | { isOk:
true; value: T } | { isOk: false; error: E }; // Result 型を使って parseEmail を定義する const parseEmail = ( unvalidatedEmail: string ): Result<ValidatedEmail, InvalidEmailFormatError> => {...} 27
??? 「今までのプログラミングと違いすぎて採用 できないよ」 28
それなら段階的に取り入れましょう 29
関数型のアイディアの段階的採用 ドメイン層から始める 関数型のアイディアは副作用のない世界ほ ど恩恵が大きい ドメイン層は副作用のあるコードがあるべ きではないのでドメイン層から始める 30
関数型のアイディアの段階的採用 Parse, don't validate から始める Parse, don't validate 自体は関数型コミュニティでのスローガンだが、コアとなる考 え方は
Always Valid Domain Model / セキュアバイデザインに近い クラス指向的な設計であっても取り入れやすいし部分的にも適用可能 クラスを使わない表現や Result 型は統一感がないと混乱を招きやすい 31
32
ご清聴ありがとうございました 33