Upgrade to Pro — share decks privately, control downloads, hide ads and more …

業務に残された「良くない型」で考える「TypeScriptの難しさ」

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for Saji Saji
May 21, 2026

 業務に残された「良くない型」で考える「TypeScriptの難しさ」

Avatar for Saji

Saji

May 21, 2026

More Decks by Saji

Other Decks in Technology

Transcript

  1. ஫ҙࣄ߲⚠ ʮ͜Μͳܕॻ͍ͯΔͳΜͯμϝʂʯͱݴ͏τʔΫͰ͸͋Γ·ͤΜʂ େࣄ  w ୭ͩͬͯ޷ΜͰas@ts-ignoreͯ͠ΔΘ͚͡Όͳ͍ w ࣗ෼ͩͬͯଟগ͸ͨ͜͠ͱ͋ΔͰ͠ΐʁ ڳʹखΛ౰ͯͳ͕Β 

    ্ڃऀͷํʹͱͬͯ͸౰ͨΓલͷ͜ͱ΋ଟ͍͔΋͠Ε·ͤΜ͕ɺ w ॳ৺Λࢥ͍ग़ͨ͠Γɺ΋ͬͱ͍͍ղܾࡦΛߟ͑ͯΈͨΓ w νʔϜͰͷӡ༻ɾޙਐҭ੒ɾ"*޲͚%PDͳͲ׆͔ͤΔͱ͜͸͋Δ͸ͣ
  2. ࠓճର৅ʹͨ͠ίʔυϕʔεͷಛ௃ Ұൠత 3FBDU54ͷҰൠతͳ$MJFOU4JEFΞϓϦߏ੒ ෳࡶͳ'PSNը໘ ೖྗͨ͠σʔλ Ϩίʔυ ͷՄࢹԽ w Ϣʔβʔ͕༷ʑͳ'JFMEͰߏஙͨ͠'PSNΛ࣮ࡍʹಈ࡞ͤ͞Δ w

    ೖྗͨ͠σʔλͷৄࡉදࣔ΍ҰཡɾάϥϑදࣔɾߜΓࠐΈͳͲ͕Ͱ͖Δ #&͔Βͷσʔλ͸جຊతʹ;PEͰ7BMJEBUJPOͯ͠Δ ஌ͬͯΔਓ޲͚LJOUPOFͷΞϓϦը໘ͷ3FBDU൛
  3. ࠓճର৅ʹͨ͠ίʔυϕʔεͷಛ௃ ಛघ ΋͔ͨ͠͠ΒҰൠతͰ͸ͳ͍͔΋͠Εͳ͍ཁ݅ w 'PSN͕ͦΕͳΓʹෳࡶ w fi FMEͷछྨׂ͕ͱଟ͍ छྨҎ্ 

    w ςʔϒϧͷதʹ fi FMEΛ഑ஔͰ͖ΔͷͰ̍ஈͷ࠶ىతͳߏ଄͕͋Δ w ੡඼Λ+4Ͱॻ͍ͨ6TFS4DSJQU1MVHJOͰΧελϚΠζͰ͖Δػߏ w Ϣʔβʔೖྗͱ#&͔ΒͷσʔλҎ֎ʹ΋৴པͰ͖ͳ͍ڥք͕͋Δ w ྫ Ϣʔβ͔Β౉͞Εͨ$BMMCBDLͷݺͼग़͠ͱ͔
  4. ୳͠ํ ୳ͤ͞ํ ࠓͷ࣌୅͸"*͕͋ΔͷͰੵۃతʹ׆༻͠Α͏ʂ ҎԼΛूதͯ͠໢ཏతʹ୳ͤͨ͞ w @ts-ignore@ts-expect-error w asΩϟετ as constas

    unknown as౳Λআ֎  w ܕΨʔυؔ਺value is X ͋Δఔ౓ࡉ͔͘෼ྨͤ͞Δˠ෼ྨ͝ͱʹ࣮ࡍʹίʔυΛݟͯ൑அ
  5. සग़"SSBZGJMUFSJODMVEFTJT"SSBZ "SSBZͷඪ४ϝιουͰ͋Δincludes΍isArrayͳͲ͸·ͩෆศ͕͞࢒Δ w JODMVEFT͸SFBE0OMZ"SSBZͩͱϦςϥϧܕΛڧ੍ w ͔ͱ͍ͬͯɺ௨ৗͷϓϦϛςΟϒͳ഑ྻʹ͢Δͱ౰ͨΓલʹܕ͕མͪΔ const STATES = ['a',

    'b'] as const; STATES.includes(state); // state: string ͰܕΤϥʔ STATES.includes(state as 'a' | 'b'); // ← ಺ଆͰ as const fieldTypes : string = ['a', 'b']; return fieldTypes.includes(field.type) ? {...field} as Field : null // type͸stringͷ··ͳͷͰ
  6. ͓͞Β͍EJTDSJNJOBUFEVOJPO 54ʹ͸EJTDSJNJOBUFEVOJPOͱ͍͏ڧྗͳਪ࿦ػೳ͕͋Δ w VOJPOʹଐ͢Δ0CKFDUʹڞ௨͢ΔϓϩύςΟͰVOJPOΛߜΓࠐΊΔػೳ type Field = | { type:

    'TEXT'; value: string } // ← discriminant: type | { type: 'NUMBER'; value: number }; function show(f: Field) { if(f.type === "TEXT") return f.value; // string ʹ narrow }
  7. සग़ରԠ͍ͤͨ͞஋Λผʹ૊Έཱͯͯ͠·͏ ຊདྷ̍ର̍ͰରԠ͍ͤͨ͞ܕΛผʑʹ࡞੒ͯ͠͠·͏ w ޙ͔ΒͦΕͧΕͷରԠؔ܎Λิ׬͢Δ͜ͱ͸Ͱ͖ͳ͍ w ܕͱͯ͠͸୯७ͳ௚ੵʹͳͬͯ͠·͏ w const fieldType =

    MAPPING[type]; // ผͷࣜͰܭࢉ const fieldValue = convertValue(fieldValue); // ผͷࣜͰܭࢉ const field = { type: jsApiFieldType, value: jsApiValue, } as Field; // Fieldʹas͢Δ͔͠ͳ͘ͳΔ
  8. සग़ରԠ͍ͤͨ͞஋Λผʹ૊Έཱͯͯ͠·͏ TUSJOH OVNCFS 5&95 ✅ /6.#&3 ✅ TUSJOH OVNCFS 5&95

    ✅ ❌ /6.#&3 ❌ ✅ {type:'TEXT',value:string} {type:'NUMBER',value:number} type: 'TEXT' | 'NUMBER', value: string | number ✅ཉ͔ͬͨ͠ܕ EVOJPO ❌࣮ࡍͷܕ ௚ੵ
  9. සग़Ҿ਺ͷ6OJPO͔ΒฦΓ஋Λਪ࿦ͮ͠Β͍ ղܾPWFSMPBEؔ਺ͰͳΜͱ͔͢Δ ͱ͸͍͑ɺύλʔϯ͕૿͑Δͱ৑௕Τϥʔ͕গ͠Θ͔Γʹ͍͘ function validate(v: unknown, t: 'TEXT' ): Result<FieldA>;

    function validate(v: unknown, t: 'NUMBER'): Result<FieldB>; function validate(v: unknown, t: string): Result<FieldA | FieldB> { return ok({ value: String(v), type: t }); }
  10. සग़ δΣωϦοΫͳҾ਺ͰϋϯυϥΛݺͿ ͬ͘͟Γ࣮૷ͯ͠ΈΔͱ͜͏ͳΓͦ͏ type Apis = { "getId" :() =>string

    .... } const callHandler = async <K extends keyof Apis>({ apiPath, // K apiArgs // Parameters<Apis[K]> }: JsApiCallData[K]) => { const handler = apiHandlers[apiPath]; // Apis[K] return await handler(...apiArgs); // Τϥʔ !! };
  11. සग़ δΣωϦοΫͳҾ਺ͰDBMMCBDLΛݺͿ ͳΜͰΤϥʔʹͳͬͯΔͷ͔ w ࣮૷ΛݟΔͱ w LFZ͔ΒҾ͍͖ͯͨϋϯυϥͷܕ͸֤ϋϯυϥ ؔ਺ ͷ6OJPOApis[K] w

    Ҿ਺͸ϋϯυϥ͕ظ଴͢ΔҾ਺ͷ6OJPOParameters<Apis[K]> w ొ࿥͞Εͨϋϯυϥ͕ड͚෇͚ΔҾ਺ܕશҾ਺ܕͷJOUFSTFDUJPO ൓ม  w ʮશҾ਺ܕͷJOUFSTFDUJPOʯWTʮϋϯυϥ͕ظ଴͢ΔҾ਺ͷ6OJPOʯ w ˠΤϥʔʂ
  12. ࠓճ঺հͨ͠ύλʔϯΛ෼ྨͯ͠ΈΔ ԡ͠໭ͤΔ ԡ͠໭ͤͳ͍ ڥք༝དྷ ಺෦༝དྷ " ࣮͸͸͋·Γͳ͍ $ # w

    %0.&WFOUDBUDI w จࣈྻˠ#SBOEFE w VOLOXPOͰͷBT w fi MUFSJODMVEFT wGSPN&OUSJFT w%JTDSJNJOBUFEVOJPOͷੜ੒ w Ҿ਺ʹԠͨ͡ฦΓ஋ਪ࿦ w δΣωϦοΫͳҾ਺ͱϋϯυϥʔ
  13. ӡ༻ʹ޲͚ͯ MJOUͰن໿Խ͢Δ w CBOUTDPNNFOUSVMF @ts-expect-erroSͰίϝϯτΛڧ੍ ΨΠυϥΠϯʹ໌ه w ྫ 'PSN fi

    FMEม׵͸GBDUPSZʹू໿͢Δ͜ͱ ఆظతͳ୨Է͠ w QSPEVDUJPOͷas@ts-ignoreΛ൒೥ʙ೥Ͱ୨Է͠
  14. ࠶ܝ୳͠ํ ୳ͤ͞ํ ࠓͷ࣌୅͸"*͕͋ΔͷͰੵۃతʹ׆༻͠Α͏ʂ ҎԼΛूதͯ͠໢ཏతʹ୳ͤͨ͞ w @ts-ignore@ts-expect-error w BTΩϟετ as constas

    unknown as౳Λআ֎  w ܕΨʔυؔ਺value is X ͋Δఔ౓ࡉ͔͘෼ྨͤ͞Δˠ෼ྨ͝ͱʹ࣮ࢪʹίʔυΛݟͯ൑அ