Slide 1

Slide 1 text

+BWB4DSJQU࣮૷ͷ ࣗ࡞ϓϩάϥϛϯάݴޠΛ 5ZQF4DSJQU࣮૷ʹҠߦͨ͠࿩ ,FJTVLF*LFEB 54,BJHJ !JLF@LFJDIBO

Slide 2

Slide 2 text

自己紹介 02/14 ɾ౦ژͱؔ੢ʢେࡕ&ژ౎ʣͷ2ڌ఺ੜ׆த ɾTSKaigi 2025,2026 / ϑϩϯτΤϯυΧϯϑΝϨϯεؔ੢ 2025,2026 ɹ3FBDU5PLZPϑΣεͷελοϑ ɾษڧձ/ΧϯϑΝϨϯεେ޷͖Ϛϯ, ΠϕϯτதͷπΠʔτ͕͏Δ͍͞ ɾࠓ೥ɺ࢈·Εͨ໑ͱै໑͕͔Θ͍͍ͱࢥ͍ͬͯΔ !JLF@LFJDIBO ,FJTVLF*LFEB

Slide 3

Slide 3 text

tsconfigに向き合おう! 03/14 ͜ͷൃදͰߦ͏͜ͱ ✅ ͢Δ͜ͱ ɾJS → TSҠߦͷ࣮ମݧ ɾݴޠ࣮૷ͱ͍͏υϝΠϯͰͷTSͷخ͔ͬͨ͠ɺͭ·͍ͮͨ࿩ 🚫 ɾࣗ࡞ͨ͠ݴޠɺࣗ࡞ͷϞσϧʹͨ͠ݴޠɺݴޠॲཧܥͷৄ͍͠࿩ ɾTypeScript ͷجຊతͳ࢖͍ํͷઆ໌ !JLF@LFJDIBO

Slide 4

Slide 4 text

前提知識 04/14 Έͳ͞Μ ϓϩάϥϛϯάݴޠ ݴޠॲཧܥ ࣗ࡞ͨ͜͠ͱ͋Γ·͔͢ʁ !JLF@LFJDIBO

Slide 5

Slide 5 text

前提知識 05/14 ɾ1958೥ John McCarthy ͞Μͷ࿦จͰൃද ɾؔ਺ܕϓϩάϥϛϯάݴޠͷϧʔπ ɾߏจ͕ඇৗʹγϯϓϧɿS ࣜʢલஔه๏ʣ ɹˠ ࣗ࡞ϓϩάϥϛϯάݴޠɾݴޠॲཧܥͷೖ໳ʹ࠾༻͞Ε΍͍͢ ࣗ࡞ݴޠͷϞσϧ-JTQʹ͍ͭͯ !JLF@LFJDIBO (+ 1 2) (* (+ 3 4) (- 10 (* 2 3)))

Slide 6

Slide 6 text

前提知識 06/14 ίʔυ͕ಈ͘·Ͱ !JLF@LFJDIBO ιʔεจࣈྻ (* (+ 3 4) (- 10 (* 2 3))) ࣈ۟ղੳʢLexerʣ τʔΫϯྻ [ *, (, +, 3, 4, ), (, -, 10, ... ] ߏจղੳʢParserʣ ASTʢ໦ߏ଄ʣ * + - 3 4 10 ... ධՁʢEvaluatorʣ ஋ 28

Slide 7

Slide 7 text

JSで苦しんだ話 07/14 +4Ͱۤ͠Μͩ࿩ index.js const eval = (node, env) => { // node は以下のいずれか: // number | string | symbol(識別子)| list | nil // // JS は引数に型を持たない // 型の検証はすべて実行時 };

Slide 8

Slide 8 text

JSで辛かった話 08/14 ܕͷෆҰக͕఻೻ index.js const eval = (node, env) => { if (node.type === "number") return node.value; if (node.type === "list") return apply(evaluate(node.car, env), node.cdr); // symbol(識別子)の処理が抜けている // return 文なし → undefined を返す // → apply の第1引数が undefined に // → 再帰の数段後で TypeError };

Slide 9

Slide 9 text

TSに移行して 09/14 !JLF@LFJDIBO ܕʹΑΔදݱ // BNF ::= | | | | nil // TypeScript type LispValue = number | string | Symbol | Cons | null; ɾBNFʢBackus-Naur Formʣɿݴޠͷจ๏Λܗࣜతʹهड़͢Δه๏ ɾBNF ͷ"|"΋ TypeScript ͷϢχΦϯܕ΋௚࿨ܕʢSum TypeʣΛදݱ ɾݴޠ࣮૷ͱ͍͏ෳࡶͳυϝΠϯʹ΋ରԠ͠΍͍͢

Slide 10

Slide 10 text

TSに移行して 10/14 !JLF@LFJDIBO 5ZQF4DSJQUͷ/BSSPXJOHʢ௨ৗ࣌ʣ index.ts // ローカル変数:TypeScript が正確に追跡できる let token: string | null = null; token = "hello"; token.toUpperCase(); // ✓ string と確定 token = null; token.toUpperCase(); // ✗ コンパイルエラー:null の可能性

Slide 11

Slide 11 text

TSに移行して 11/14 !JLF@LFJDIBO 5ZQF4DSJQUͷ/BSSPXJOHʢDMBTT಺ʣ index.ts class Lexer { private token: string | null = null; private readNext(): void { this.token = "hello"; // フィールドを書き換える副作用 } next(): void { this.token = null; // TypeScript:token は null と記録 // ... // readNext() の中身は解析しない // → this.token が書き換わることを TypeScript は追跡できない } }

Slide 12

Slide 12 text

TSに移行して 12/14 !JLF@LFJDIBO 54Ͱۤ͠Μͩ࿩ index.ts class Parser { private current: LispValue = null; // 完成したトークンを格納 private state: number = 0; private consume(): void { // 1文字読み進め、トークンが完成したら this.current に格納 } nextToken(): LispValue { this.current = null; // ① TypeScript:current は null と記録 while (!this.done()) { if (this.current !== null) break; // ② TypeScript:常に false と警告 this.consume(); // ③ this.current を書き換えるが追跡されない } return this.current; } }

Slide 13

Slide 13 text

TSに移行して 13/14 !JLF@LFJDIBO 54ͱͯ͠ਖ਼͍͠001ઃܭ index.ts class Parser { private current: LispValue = null; // 完成したトークンを格納 private state: number = 0; private consume(): void { // 1文字読み進め、トークンが完成したら this.current に格納 } nextToken(): LispValue { this.current = null; // ① TypeScript:current は null と記録 while (!this.done()) { if (this.current !== null) break; // ② TypeScript:常に false と警告 this.consume(); // ③ this.current を書き換えるが追跡されない } return this.current; } }

Slide 14

Slide 14 text

まとめ 14/14 !JLF@LFJDIBO ·ͱΊ ɾ+4࣮૷࣌͸ܕͷෆҰக͕VOEFGJOFEͱͯ͠੩͔ʹ఻೻ͤ͞ΔɻΤϥʔͷ ɹݪҼՕॴͱൃੜՕॴ͕ͣΕͯਏ͍😭 ɾจ๏هड़ʢ#/'ʣͱϢχΦϯܕ͸௚࿨ܕʢ4VN5ZQFʣͱͯ͠ࣅͨߏ଄Λ ɹ࣋ͭɻܕʹΑΔ੍໿Ͱ࣮ߦલʹ໰୊ʹؾ͚ͮΔ😎 ɾ/BSSPXJOH͸ϝιουݺͼग़͠ޙͷϑΟʔϧυมߋΛ௥੻͠ͳ͍ɻ001 ɹͷঢ়ଶ؅ཧͱিಥ͢Δ😵

Slide 15

Slide 15 text

宣伝 ϑϩϯτΤϯυΧϯϑΝϨϯεؔ੢ 2026 ଓใ͸SNSͰ֬ೝͯ͠΍ʙ X note