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

スキーマと型で拓く Full-Stack TypeScript / TSKaigi 2025

Avatar for Altech Altech
May 22, 2025

スキーマと型で拓く Full-Stack TypeScript / TSKaigi 2025

TS Kaigi 2015 でお話しした資料です。
https://2025.tskaigi.org/talks/Altech_2015

Avatar for Altech

Altech

May 22, 2025
Tweet

More Decks by Altech

Other Decks in Technology

Transcript

  1. ࣗݾ঺հ  • 4PIFJ5BLFOP • 4"/6 d  • ࠷ॳͷιϑτ΢ΣΞΤϯδχΞͱͯ͠ࢀը

    • ιϑτ΢ΣΞྖҬͷٕज़͓Αͼ૊৫ͷ಺੡Խ • 8BOUFEMZ d  • ϓϩμΫτ։ൃɾٕज़ج൫ɾϚωδϝϯτͳͲ • ٕज़ɿ3VCZˠ3VCZ 5ZQF4DSJQU (P 1ZUIPO(SBQI2- H31$ • ຊൃද͸4"/6ʹ͓͚ΔऔΓ૊ΈͰ͕͢ɺલ৬ʹ͓͚Δܦݧ΍ಉ࣌୅ͷଞࣾͷऔΓ ૊Έ͔Βଟ͘ͷώϯτΛಘ͍ͯ·͢💡 !"MUFDI@
  2. ࣄۀల։ͷதͰϑϧϦϓϨΠεΛ࣮ࢪ  • ࠓޙͷల։Λ౿·͑ͯϑϧϦϓϨΠεΛ։࢝ˠ'VMM4UBDL5ZQF4DSJQUΛ࠾༻ • ࣄۀతʹ΋֦େϑΣʔζͷͨΊ৽αʔϏεల։ʢچγεςϜͷ։ൃʣͱฒߦͯ͠৽γες ϜΛ։ൃɺ೥൒ޙʹҠߦͨ͠ ͜ͷΑ͏ͳڧ౓͕ཁٻ͞ΕΔ։ൃʹ͓͍ͯεΩʔϚۦಈͷ'VMM4UBDL54͕େ׆༂🌸 ڌ఺਺ 

     ݐஙϞσϧ਺   αʔϏεܗଶ αϒεΫ ୯ധɾαϒεΫɾڞಉॴ༗ɾ౩ॴ༗ ҠߦݩγεςϜن໛ ΧϥϜ ΧϥϜ اۀϑΣʔζ γϦʔζ" γϦʔζ#Ϋϩʔζ ༨ஊɿϊʔίʔυͰԯҎ্ௐୡͨ͠ࠃ಺།ҰͷαʔϏε😁
  3. Ұา໭ͬͯ༻ޠఆٛɿ ΫϥΠΞϯταΠυαʔόʔαΠυɺϑϩϯτΤϯυόοΫΤϯυ  ϥϯλΠϜ۠෼ ੹຿ͷҧ͍ ΫϥΠΞϯταΠυ αʔόʔαΠυ ϑϩϯτΤϯυ όοΫΤϯυ ɾϢʔβʔͱ઀఺Λ࣋ͭ

    6*  ɾ࣮ࡏͱମݧΛ૑Γग़͢ 69 ɾϏδωεϧʔϧΛ಺แ ɾσʔλϕʔεͱ௚઀࿈ܞ ɾखݩͷσόΠεͰಈ࡞ ɾωοτϫʔΫͷઌͰಈ࡞ ▶︎ ͜ͷೋ͕ͭϓϩάϥϜߏ଄্΋໌֬ʹ෼͔ΕΔ͔͸ઃܭ্ͷબ୒ʹͳΔ
  4. ෼཭ٕज़ͱͯ͠ͷ(SBQI2-ʹ͍ͭͯ  • ιϑτ΢ΣΞͷΠϯλʔϑΣΠεΛεΩʔϚͱͯ͠ఆٛ͢Δ • όοΫΤϯυ͸εΩʔϚΛຬͨ͢Α͏ʹ࣮૷͢Δ • ϑϩϯτΤϯυ͸εΩʔϚΛݩʹΫΤϦΛൃߦ͢Δ • ࣮૷͕ΠϯλʔϑΣΠεʹґଘ͢ΔͨΊɺద੾ʹεΩʔϚΛઃܭ͢Δ͜ͱͰૄ݁߹ͷԸܙ͕͋Δ

    (SBQI2-ΫΤϦ query SanuAreas { areas { name sites { name rooms { code } } } } { "data": { "areas": [ { "name": "ീϲַ", "sites": [ { "name": "ീϲַ 1st", "rooms": [ { "code": "0103" }, { "code": "0102" } (SBQI2-Ϩεϙϯε
  5. ਐԽ͢ΔΞʔΩςΫνϟɿ ϑϩϯτΤϯυͷଟ༷Խ  • Ϣʔεέʔε΍؀ڥʹԠͯ͡ҟͳΔ ϑϩϯτΤϯυΛఏڙ͍ͯ͘͠έʔε • ࠷దͳٕज़͕54ͱ͸ݶΒͳ͍ • ࣮ࡍ4"/6Ͱ͸؅ཧ༻ΞϓϦʹ

    ϩʔίʔυٕज़ 3FUPPM Λ࠾༻ • (SBQI2-Ͱ͸ఏڙ͢Δ৘ใ͕ಉ͡Ͱ͋Ε ͹όοΫΤϯυͷมߋͳ͠Ͱల։Ͱ͖Δ ݱ୅ͷ8FCαʔϏε͸࣮ࣾձͷଟ༷ͳεςʔΫϗϧμʔΛר͖ࠐΜͰ՝୊Λղܾ͢Δέʔε΋ଟ͘ͳ͍ͬͯΔͨΊɺ γεςϜ͸ڞ௨͕ͩҟͳΔΞϓϦΛఏڙ͢Δɺͱ͍ͬͨ͜ͱ͸4"/6ʹݶΒͣҙ֎ͱଟ͍ͷͰ͸ͳ͍Ͱ͠ΐ͏͔
  6. εϐʔυΛ٘ਜ਼ʹ͠ͳ͍ͭͷ޻෉  όοΫΤϯυͱϑϩϯτΤϯυΛ෼͚Δ͜ͱͰൃੜ͢ΔΦʔόʔϔουʹରॲɿ • ։ൃ࣌ɿαʔόʔͷىಈɾ࿈ܞ͕໘౗ʹͳΔ • ➡ϑϩϯτΤϯυͷ/FYUKTαʔόʔʹόοΫΤϯυಉࠝ✅ίϚϯυͰىಈɾऴྃ • ӡ༻࣌ɿΠϯϑϥ΍$*$%͕ෳࡶʹ •

    ➡ϞϊϨϙΛ7FSDFMʹ࿈ܞͯ͠αʔόϨεʹ͓೚ͤ • ✅ચ࿅͞Εͨ։ൃϓϥοτϑΥʔϜͰɺΤϯδχΞ͸ϓϩμΫτ։ൃʹूத • ࣮ߦ࣌ɿωοτϫʔΫΛܦ༝͢Δ͜ͱʹΑΔίετɾ଎౓૿ • ➡αʔόʔαΠυ͔Βͷ(SBQI2-ݺͼग़͠͸τϥϯεϙʔτ૚Λ)551͔Βࠩ͠ସ͑ • ✅༨෼ͳαʔόϨεɾϑΝϯΫγϣϯͷىಈΛ཈͑Δ͜ͱ͕Ͱ͖ͨ
  7. type Query { areas: [Area!]! } """ΤϦΞʢྫɿീϲַ,Տޱބʣ""" type Area {

    name: String! sites: [Site!]! } """ڌ఺ʢྫɿീϲַ1st,ീϲַ2ndʣ""" type Site { nth: String! rooms: [Room!]! } """෦԰""" type Room { Code: String! } (SBQI2-εΩʔϚΛఆٛ͢Δ  • ΤϯτϦϙΠϯτΛఆٛ • ֤ΦϒδΣΫτΛఆٛ • ೔ຊޠ΋ซه͢Δ • ϢϏΩλεݴޠͷఆٛʹͳΔ • ΦϒδΣΫτಉ࢜Λܨ͙ schema.graphql
  8. όοΫΤϯυɿڌ఺ʹؚ·ΕΔ෦԰ΛऔಘͰ͖ΔΑ͏ʹ͢Δྫ  • (SBQI2-$PEFHFO4FSWFS1SFTFUͰ਽ܗΛίʔυੜ੒ import type { SiteResolvers } from

    "../__generated__/types"; export const Site: SiteResolvers = { rooms: async (parent, _arg, ctx) => { // Implementation of the resolver. // // // // }, }; resolvers/Site.ts
  9. όοΫΤϯυɿڌ఺ʹؚ·ΕΔ෦԰ΛऔಘͰ͖ΔΑ͏ʹ͢Δྫ  • (SBQI2-$PEFHFO4FSWFS1SFTFUͰ਽ܗΛίʔυੜ੒ import type { SiteResolvers } from

    "../__generated__/types"; export const Site: SiteResolvers = { rooms: async (parent, _arg, ctx) => { // Implementation of the resolver. // // // // }, }; resolvers/Site.ts • ੜ੒͞Εͨ਽ܗʹରͯ͠σʔλϑΣονΛ࣮૷ • ͜ͷ৔߹͸σʔλϕʔεͱͷ΍ΓऔΓʹ1SJTNBΛར༻͍ͯ͠Δ return ctx.prisma.room.findMany({ where: { siteId: parent.id, }, });
  10. ϑϩϯτΤϯυɿ෦԰Λදࣔ͢Δίϯϙʔωϯτͷྫ  • 3FBDUίϯϙʔωϯτͷϑΝΠϧʹ ࢀর͢Δ(SBQI2-ͷσʔλ΋ఆٛ • 'SBHNFOU$PMPDBUJPOͱ͍͏ඞਢख๏ const Fragment =

    graphql(` fragment RoomForCalendar on Room { code } `); type Props = { FragmentType<typeof Fragment> }; export function Room({ roomData }: Props) { const room = useFragment(Fragment, roomData); return ( <div style={roomStyle}> {room.code} </div> ); } room.tsx
  11. ϑϩϯτΤϯυɿ෦԰Λදࣔ͢Δίϯϙʔωϯτͷྫ  • ྫɿ෦԰ʹઃඋ͕෇͍ͨ৔߹ͷରԠ • มߋ͕ίϯϙʔωϯτͰ׬݁͢Δ✅ const Fragment = graphql(`

    fragment RoomForCalendar on Room { code facility { name type } } `); type Props = { FragmentType<typeof Fragment> }; export function Room({ roomData }: Props) { const room = useFragment(Fragment, roomData); return ( <div style={roomStyle}> {room.code} {facilityIcon(room.facility.type)} {facilityLabel(room.facility.type)} </div> ); } room.tsx
  12. 6OJPOܕΛ׆༻ͨ͠ࣄۀల։ɿεΩʔϚϨϕϧ  αʔϏεϓϥϯΛ6OJPOܕͰϞσϦϯάͯ͠௥Ճ͍ͯ͘͠ ॳظͷεΩʔϚఆٛɿ ݱࡏͷεΩʔϚఆٛɿ union ServiceProvider = | SubscriptionProvider

    | BusinessProvider | CoOwnersProvider | FullOwnersProvider | StayProvider # ৽αʔϏε # ৽αʔϏε # ৽αʔϏε union ServiceProvider = | SubscriptionProvider | BusinessProvider schema.graphql schema.graphql
  13. αʔόʔαΠυʹ͓͚Δ(SBQI2-ݺͼग़͠  import { YogaLink } from "@graphql-yoga/apollo-link"; function createApolloClientForServer(...)

    { return new ApolloClient({ // มߋ఺͸͜Ε͚ͩ link: new YogaLink({ fetch: yoga.fetch, endpoint: yoga.graphqlEndpoint, }), // ... }); } ɾ"QPMMP$MJFOUͷMJOLΛมߋ͢Δ͜ͱͰΠϯϓϩηεʹͰ͖Δ
  14. (SBQI2-ؔ࿈ͷ͓͢͢Ίࢿྉू • 5ZQF4DSJQUͱ(SBQI2-Ͱ࣮ݱ͢Δܕ҆શͳ"1*࣮૷ • IUUQT[FOOEFWVCJF@EFWBSUJDMFTBEFFFF • (SBQI2-ͷޡղSFUIJOLJOHHSBQIRM • IUUQTTQFBLFSEFDLDPNTPOBUBSESFUIJOLJOHHSBQIRM •

    1SPEVDUJPO3FBEZ(SBQI2- • IUUQTCPPLQSPEVDUJPOSFBEZHSBQIRMDPN • (SBQI2-͋Δ͍͸3FBDUʹ͓͚Δࣗ཯తͳσʔλऔಘʹ͍ͭͯ • IUUQTTQFBLFSEFDLDPNRVSBNZGSBHNFOUDPNQPTJUJPOPGHSBQIRM • (SBQI2-αʔόͷߏ੒ཁૉΛ੔ཧ͢Δ • IUUQTTQFBLFSEFDLDPNJ[VNJOHSBQIRMTFSWFSUFDIOPMPHZTFMFDUJPO