$30 off During Our Annual Pro Sale. View Details »

プロダクト開発とTypeScript

 プロダクト開発とTypeScript

TypeScriptによるプロダクト開発の知見

More Decks by Taketoshi Aono(青野健利 a.k.a brn)

Other Decks in Programming

Transcript

  1. Product development with TypeScript

    View Slide

  2. Name
    !CSO 5BLFUPTIJ"POP੨໺݈ར

    Occupation
    'SPOUFOE%FWFMPQFS1SPEVDU0XOFS
    Company
    $ZCFSBHFOU"EUFDI4UVEJP"*.FTTFOHFS
    OSS
    $POUSJCVUPSPG7
    About
    IUUQJOGPCODI

    View Slide

  3. 1SPEVDUEFWFMPQFEFGGFDUJWFMZ
    5ZQF4DSJQUಋೖͯ͠ϓϩμΫτ։ൃͷੜ࢈ੑ͸্͕Γ·͔ͨ͠ʁ
    ಋೖ͚ͨͩ͠Ͱ͸ͳ͔ͳ͔೉͍͔͠΋͠Ε·ͤΜɻ
    ࠓ೔ͷτʔΫ͕
    ੜ࢈ੑΛͰ͖Δ্͚ͩ͛ΔͨΊͷΨΠυͱͳΔ͜ͱΛئ͍·͢ɻ

    View Slide

  4. *NQPSUBOUUIJOHTBCPVU5ZQF4DSJQU
    5ZQF4DSJQUͷॏཁͳ఺Ͱ͢
    KBWBTDSJQUͰ͸ͳ͍͕KBWBTDSJQUͰ΋͋Δ
    ܕ͸࣮ߦ࣌ʹ͸ফ͑Δ

    View Slide

  5. ػೳ

    View Slide

  6. #FGPSFBMM
    લఏͱͯ͠UTDPOpHKTPOͰҎԼͷػೳ͸ඞͣ0/ʹ͠·͠ΐ͏
    OP*NQMJDJU"OZ
    TUSJDU

    View Slide

  7. *NQPSUBOUUIJOHTBCPVU5ZQF4DSJQU
    KBWBTDSJQUͰ͸ͳ͍͕KBWBTDSJQUͰ΋͋Δ
    5ZQF4DSJQU͸KBWBTDSJQUͷ4VQFS4FUΛᨳ͍ͬͯ·͢
    ͦͷͨΊ࢓༷తʹ͸+BWBTDSJQUΛ౿ऻ͍ͯ͠·͕͢
    ͋͘·Ͱผͷݴޠͱଊ͑ͨ΄͏͕ྑ͍Ͱ͢
    ͦͷ্Ͱ͍͔ͭ͘ॏཁͳ఺ʹ͍͓ͭͯ࿩͠·͢

    View Slide

  8. FOVN
    FOVN͸5ZQF4DSJQUͷಠࣗػೳͰ͢ KBWBTDSJQUʹ͸ແ͍ͱ͍͏ҙຯࠓޙ΋ಉ
    ͡ҙຯͰ࢖͍·͢

    View Slide

  9. enum Card {
    SPADE,
    HEART,
    DIAMOND,
    CLUB
    }
    // ࿈൪
    assert.equal(Card.SPADE, 0);
    assert.equal(Card.DIAMOND, 2);
    // ٯҾ͖
    assert.equal(Card[Card.DIAMOND], 'DIAMOND');

    View Slide

  10. enum Event {
    CLICK = 'CLICK',
    MOUSEOVER = 'MOUSEOVER';
    }

    View Slide

  11. FOVN
    FOVN͸͜ͷΑ͏ʹ஋Λ·ͱΊΔͷʹར༻͠·͕͢
    FOVNࣗ਎͕ܕΛߏ੒͠ɺܕνΣοΫʹར༻Ͱ͖·͢
    ͨͩ͠஫ҙ఺͕͋Γ·͢

    View Slide

  12. enum Card {
    SPADE,
    HEART,
    DIAMOND,
    CLUB
    }
    const fn = (card: Card) => { return card; }
    fn(Card.SPADE); // OK
    fn(0); // OK
    fn(10); // OK

    View Slide

  13. FOVN
    FOVNΛͦͷ··ར༻͢Δͱɺ୯७ͳOVNCFSܕͱͳΓ਺஋ͷൣғΛνΣο
    Ϋͯ͘͠Ε·ͤΜ
    ͦͷͨΊෆਖ਼ͳ஋Λ౉͢͜ͱ΋ՄೳʹͳΓ·͢

    View Slide

  14. enum EventType {
    CLICK = 'CLICK',
    MOUSEOVER = 'MOUSEOVER';
    }
    const fn2 = (event: EventType) => {return event;}
    fn2(EventType.CLICK);
    fn2(EventType.MOUSEOVER);
    fn2("MOUSEDOWN"); // NG

    View Slide

  15. FOVN
    จࣈྻ஋Λ࢖ͬͨ৔߹ʹ͸ਖ਼͘͠FOVNʹఆٛ͞Ε͍ͯΔ஋ͷνΣοΫΛߦ
    ͍·͢
    ·ͨ஋Λܕͱͯ͠࢖͏͜ͱͰ5BHHFE6OJPOͱͯ͠΋࢖͏͜ͱ͕Ͱ͖·͢

    View Slide

  16. enum EventType {
    CLICK = 'CLICK',
    MOUSEOVER = 'MOUSEOVER';
    }
    interface ClickEvent {
    type: EventType.CLICK;
    }
    interface MouseDownEvent {
    type: EventType.MOUSEOVER;
    }
    declare const clickEvent: ClickEvent;
    declare const mouseDownEvent: MouseDownEvent;
    const fn3 = (event: ClickEvent) => { return event; }
    fn3(clickEvent); // OK
    fn3(mouseDownEvent); // NG

    View Slide

  17. FOVN
    FOVN͸ศརͰ͕͢ɺ਺஋ͷ৔߹͸ܕ͚ͩͰ͸੍ޚͰ͖ͳ͍ͷͰɺ
    ਺஋ͱͯ͠ར༻͢Δ৔߹͸ݺͼग़͞ΕΔଆͰൣғͷνΣοΫΛ͠·͠ΐ͏ɻ

    View Slide

  18. /BNFTQBDF
    OBNFTQBDF΋5ZQF4DSJQUಠࣗػೳͰ͕͢
    &4.PEVMFTͷ͓͔͛Ͱ༨Γ࢖͏ҙຯ͸ͳ͘ͳΓ·ͨ͠
    ͜ͷػೳ͸એݴϑΝΠϧҎ֎Ͱ࢖͏ͷ͸ࠞཚͷݩͳͷͰ࢖͏ඞཁ͸ͳ͍Ͱ
    ͠ΐ͏

    View Slide

  19. /VMMPSVOEFpOFE
    KBWBTDSJQUʹ͸ͭͷແޮͳ஋͕͋Γ·͢
    OVMMͱVOEFpOFEͰ͢
    VOEFpOFE͸஋͕ະఆٛͷ৔߹ʹར༻͞ΕɺOVMM͸݁Ռ͕ଘࡏ͠ͳ͍࣌ʹ࢖
    ΘΕ·͢
    ͕ͦͷ࢖͍෼͚ʹରͨ͠ҙຯ͸͋Γ·ͤΜ
    ࠞཚ͢Δ͚ͩͰ͢

    View Slide

  20. *O5ZQF4DSJQU
    OVMM΍VOEFpOFE͸5ZQF4DSJQU্Ͱ΋΍΍໘౗Ͱ͢
    TUJSDU/VMM$IFDLT͸0/ʹ͢΂͖Ͱ͕͢ɺVOEFpOFEͷνΣοΫ͸͞Ε·ͤΜ

    View Slide

  21. .BZCFPS0QUJPOBM
    OVMMɺVOEFpOFE͸XSBQͯ͠͠·͍·͠ΐ͏ɹ

    View Slide

  22. type Optional = T | undefined | null;

    View Slide

  23. 0QUJPOBM
    ຊདྷ0QUJPOBM͸Ϋϥεʹͯ͠͠·͍͍ͨͱ͜ΖͰ͕͢
    5ZQF4DSJQUͰ0QUJPOBM$IBJOJOH͕ೖΔͷͰ
    ΑΓ5ZQF4DSJQUωΠςΟϒͰऔΓѻ͑Δϑϥοτͳܕͷ΄͏͕ྑ͍Ͱ͠ΐ͏

    View Slide

  24. type Optional = T | undefined | null;
    declare const obj: Optional<{value?: string}>;
    // ·ͩಈ͖·ͤΜ
    // or
    obj?.value || ‘’
    // force
    obj!.value!

    View Slide

  25. ࣮૷

    View Slide

  26. %FWFMPQXJUI5ZQF4DSJQU
    5ZQF4DSJQUΛ࢖ͬͯ։ൃ͢Δ৔߹ͷ࣮૷खॱ͸KBWBTDSJQUͱ͸େ͖͘ม͑·
    ͠ΐ͏

    View Slide

  27. *OUFSGBDF'JSTU
    ࠷΋େࣄͳ͜ͱ͸ந৅తͳ࣮૷Λ࠷ॳʹߦ͏͜ͱͰ͢
    ͦΕ͸ͭ·Γ۩ମతͳϩδοΫ͔Β཭ΕΔ͜ͱͰ͢
    5ZQF4DSJQU͸JOUFSGBDFͱUZQFʹΑͬͯͦΕΛՄೳʹ͍ͯ͠·͢
    ِ3FEVYΈ͍ͨͳྫΛ঺հ͠·͢

    View Slide

  28. interface Todo {
    id: string;
    date: Date;
    title: string;
    done: boolean;
    }
    type Todos = Todo[];
    interface State {
    todos: Todos;
    }
    type Payload = {
    type: "ADD",
    } | {
    type: "DELETE"
    payload: {id: string};
    }
    const reducer = (payload: Payload, state: State): State => {
    return state;
    }

    View Slide

  29. -PHJDJTMBUFS
    SFEVDFSͷ࣮૷Ҏ֎͸શͯܕͷΈͰ࣮૷͞Ε͍ͯ·͢
    SFEVDFS΋த਎͸ۭͰ஋Λฦ͚ͩ͢Ͱ͢
    ͔͜͠͠ΕͰϓϩάϥϜͷࠎ͸Ͱ͖͍ͯ·͢
    ͋ͱ͸SFEVDFSͷ࣮૷ʹूத͢Δ͚ͩͰ͢

    View Slide

  30. -PHJDJTMBUFS
    ۃ୺ͳ࿩۩ମతͳΞϧΰϦζϜ͸͋·ΓॏཁͰ͸͋Γ·ͤΜ
    σʔλߏ଄ɾܕ͕΋ͬͱ΋ॏཁͰ͢
    ͕ܾ͜͜·Ε͹େ֓ΞϧΰϦζϜ͸ࣗવͱಋ͔Ε·͢

    View Slide

  31. ڥք

    View Slide

  32. 7JSUVBMBOE3FBM
    ࠷ॳʹड़΂ͨΑ͏ʹ5ZQF4DSJQU͸͋͘·ͰԾ૝ͷܕΛ࣋ͭݴޠͰ͢
    ͦͷͨΊɺ࣮ࡍʹ࣮ߦ͞ΕΔ৔߹ʹ͸஋ͱܕͷဃ཭͕ى͖ΔՄೳੑ͕͋Γ·
    ͢

    View Slide

  33. 4FQBSBUFE8PSME
    ಛʹဃ཭͕ى͖΍͍͢ͷ͕ɺ֎෦ͱͷڥքͱͳΔ෦෼Ͱ͢
    "1*αʔόͱͷڥք
    ϒϥ΢βετϨʔδͱͷڥք

    View Slide

  34. "EBQUFS
    ͨͩ͠ɺٯʹݴ͑͹͜ΕΒͷڥք͑͞཈͑ͯɺઌఔͷJOUFSGBDFઌߦͷ࣮૷
    Λߦ͑͹ဃ཭Λ΁Β͢͜ͱ͕Ͱ͖ΔͷͰ͸ͳ͍Ͱ͠ΐ͏͔ʁ
    ·ͨ1SPUP#VGͷΑ͏ͳ54ࣗಈੜ੒ܥΛ࢖͏ͷ΋खͰ͢

    View Slide

  35. 1SPHSBN
    1SPHSBN
    1SPHSBN
    "EBQUFS
    &YUFSOBM*OUFSGBDF

    View Slide

  36. $MFBO"SDIJUFDUVSF
    ·ΔͰ$MFBO"SDIJUFDUVSFͷϨΠϠʔਤͷΑ͏ʹͳΓ·ͨ͠
    ͔͠͠ɺผʹ$MFBO"SDIJUFDUVSFΛར༻͠Ζͱݴ͍ͬͯΔΘ͚Ͱ͸ͳ͘
    5ZQF4DSJQUͷԾ૝ܕͱ͍͏࢓૊Έʹͱͬͯ΋"EBQUFS͸ඇৗʹॏཁͳҙຯΛ
    ࣋ͪ·͢
    ͲΜͳΞʔΩςΫνϟΛ࠾༻͍ͯͯ͠΋֎෦γεςϜڥքΛਖ਼͘͠཈͑Δ͜
    ͱͰɺ5ZQF4DSJQUͷܕ͸ΑΓҰ૚໾ཱͭͰ͠ΐ͏

    View Slide

  37. 5P5ZQFE
    ࠓ·Ͱͷ࿩͸࠷ॳ͔Β5ZQF4DSJQUͰ։ൃ͍ͯ͠ΔέʔεΛલఏͱ͍ͯ͠·͢
    ͕
    ΋͠طଘͷKBWBTDSJQU͔ΒҠߦ͢Δ৔߹΋֎෦ڥք͔ΒܕΛ෇͚͍ͯ͘ͱΑ
    ͍Ͱ͠ΐ͏
    ·ͨɺਖ਼͍͔ͨ͠ͱਖ਼͘͠ͳ͍ܕΛڥքΛه࿥͓ͯ͘͜͠ͱ͕େࣄͰ͢

    View Slide

  38. "OZBEBQUFS
    ܕ෇͚͞Ε͍ͯͳ͍ةݥͳྖҬ͸શͯɺਖ਼͍͠ܕ͔Βม׵ͨ͠ͱ͍͏໨ҹΛ
    ͚͓ͭͯ͘ͱϦϑΝΫλϦϯά͕͠΍͍͢Ͱ͢

    View Slide

  39. type UncheckedFixme = any;
    interface Model {}
    const unTypedFn = (a: UncheckedFixme) {
    }

    View Slide

  40. "OZBEBQUFS
    6ODIFDLFE'JYNF5͕ͲΜͲΜίʔυͷίΞྖҬʹԡ͠ࠐ·ΕΔ·ͰϦ
    ϑΝΫλϦϯά͚ͭͮ͠·͠ΐ͏
    ͦͯ͠࠷ޙʹ͸ίʔυத͔Βফͯ͠͠·͍·͠ΐ͏
    ͜ͷΑ͏ͳ#PUUPN6Qతͳܕͷ෇͚ํΛ͢Δͱɺ֎෦ͷةݥͳྖҬ͔Β҆શ
    ͳ಺෦΁ഭ͍ͬͯ͘ͷͰܕͷϛε͕ى͖ͮΒ͍Ͱ͢
    ͪͳΈʹ6ODIFDLFE'JYNF5͸-JOUΤϥʔग़ΔՄೳੑ͕͋ΔͷͰ௵͓ͯ͠
    ͍͍ͯͩ͘͞

    View Slide

  41. ίʔσΟϯά

    View Slide

  42. 5ZQFJTCPUIFS
    ܕ෇͚͸݁ߏ໘౗Ͱ͢
    ࠷ॳʹJOUFSGBDFͰܕఆٛΛͪΌΜͱ͓ͯ͘͠ͱزจ͔ղফ͸͞Ε·͕͢
    ຊ࣭తʹ෇Ճతͳ࡞ۀͳͷͰαϘΓ͕ͪͰ͢

    View Slide

  43. .BZCFXSPOH
    ͨͩɺܕ෇͚ͷ໘౗͘͞͞͸ίʔυͷ·͔ͣ͞΋͠Ε·ͤΜ

    View Slide

  44. class Test {
    private value: {[key: string]: string} | null;
    constructor() {}
    public setValue(value: {[key: string]: string}) {
    this.value = value;
    }
    public doSomething() {
    return this.value!['key'] // you need to through type check.
    }
    }

    View Slide

  45. *OJUJBMJ[FMBUFS
    ͜ͷΑ͏ͳޙʹॳظԽ͞ΕΔϝϯόม਺౳͸ܕͰදݱ͢Δͷ͕ࠔ೉Ͱ͢
    ͞Βʹ/VMMBCMF͔VOEFpOFEΛڐ༰͢Δܕʹͨ͠৔߹ʹ͍͍ͪͪ
    Λॻ͘ͷ΋ةݥ͔ͭ໘౗Ͱ͢
    ͜ͷΑ͏ͳɺͦ΋ͦ΋ܕͰදݱ͢Δͷ͕೉͍͠ίʔυΛආ͚ΔΑ͏ʹ͢Δͷ
    ͕ྑ͍Ͱ͢
    ࠓճͷέʔεͰݴ͑͹શͯDPOTUSVDUPSͰॳظԽ͢΂͖Ͱ͢

    View Slide

  46. function getValue() {
    let value: {[key: string]: number} | null = null;
    if (x) {
    value = {key: 1};
    } else {
    value = {value: 1};
    }
    return value;
    }

    View Slide

  47. *OJUJBMJ[FMBUFS
    JGจͷதͰม਺ΛॳظԽ͢ΔͷΛ͚ͯ͞ɺJGจΛؔ਺Խͯ͠͠·͍·͠ΐ͏

    View Slide

  48. .PSFUZQBCMFDPEF
    ΑΓγϯϓϧʹܕ෇͚Ͱ͖Δίʔυ͸
    ਓؒʹ΋ಡΈ΍͘͢ཧղ͠΍͍͢ίʔυͱͳΓ·͢
    ΋ͪΖΜ͖Ε͍ʹॻ͍ͯ΋ෳࡶͳܕΛ࣋ͭέʔε͸͋Γ·͢͠ɺશ͕ͯͦͷ
    ͱ͓ΓͰ͸͋Γ·ͤΜ͕
    ෳࡶͳܕػೳΛ࢖͏લʹίʔυͷߏ଄͕ਖ਼͍͔֬͠ೝͯ͠Έ·͠ΐ͏

    View Slide

  49. ·ͱΊ
    5ZQF4DSJQUͰͷ։ൃʹ͍ͭͯͷτʔΫͰͨ͠
    ͜ΕΒͷ5JQT͕͋ͳͨͷ։ൃͷखॿ͚ʹͳΔͱ޾͍Ͱ͢
    ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠

    View Slide