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

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

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 ͋Δఔ౓ࡉ͔͘෼ྨͤ͞Δˠ෼ྨ͝ͱʹ࣮ࢪʹίʔυΛݟͯ൑அ