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

コードには型アノテーションよりも要件アノテーションを増やせ!/harajukuts2

OKUNOKENTARO
January 28, 2022

 コードには型アノテーションよりも要件アノテーションを増やせ!/harajukuts2

2022/1/28 Harajuku.ts Meetup #2 にて使用した資料です。

11ページ目はString#join()ではなくArray#join()の誤りでした。お詫びいたします。

OKUNOKENTARO

January 28, 2022
Tweet

More Decks by OKUNOKENTARO

Other Decks in Technology

Transcript

  1. +BO )BSBKVLVUT.FFUVQ
    !PLVOPLFOUBSP
    ίʔ
    υʹ͸ܕΞϊςʔγϣϯΑ
    Γ
    ΋

    ཁ݅ΞϊςʔγϣϯΛ૿΍ͤ
    ʂ

    View Slide


  2. w Ԟ໺ݡଠ࿠!PLVOPLFOUBSP
    w ΫϨε΢ΣΞגࣜձࣾ
    w 5ZQF4DSJQUྺ೥
    w ϑϩϯ
    τΤϯ
    υ
    ɾ
    όοΫΤϯ
    υ

    View Slide

  3. 5ZQF4DSJQUొஃͷྺ࢙

    View Slide

  4. 5ZQF4DSJQUొஃͷྺ࢙
    ࠓ೔͸͜Εͷଓ͖Ͱ͢ˢ

    View Slide

  5. ͳͥ5ZQF4DSJQUΛ࢖͏ͷ͔
    ʁ
    w +BWB4DSJQU͸ॻ͍͍ͯͯϛεΛ͢Δݴޠ͔ͩΒͰ͋Δ
    w ΋ͪΖΜ5ZQF4DSJQU΋ॻ͍͍ͯͯϛεΛ͢ΔݴޠͰ͋Δ
    w ϛε͔ͯ͠Βϛεʹؾ෇͘
    ·Ͱͷ͕࣌ؒ୹͚Ε͹୹͍΄Ͳخ͍͠
    w ͦ΋ͦ΋ϛε͠ͳ͍Α
    ͏ͳߏจͰ͋Ε͹΋ͬͱخ͍͠
    wʮઈରʹϛεΛ͠ͳ͍ਓʯ
    ͕։ൃ͢ΔͳΒ+BWB4DSJQUͷ··͓޷͖ʹͲ͏
    ͧ

    View Slide

  6. ਓ͸ϛεΛ͢ΔΜͰ͢
    ʂ

    View Slide

  7. ۃ୺ͳྫ
    ͜Ε͸+BWB4DSJQUͷίʔ
    υ

    ͭͷ਺஋Λ଍ͯ͠߹ܭΛฦ͢add()ؔ਺
    function add(a, b) {


    return a + b;


    }

    View Slide

  8. ۃ୺ͳྫ
    Ͱ΋ add("Hello", "World") ͳΜͯ͜ͱ΋Ͱ͖Δ

    ʢ݁Ռ͸)FMMP8PSMEʣ
    function add(a, b) {


    return a + b;


    }

    View Slide

  9. ۃ୺ͳྫ
    function add(a, b) {


    return a + b;


    }
    ࣮૷ऀ͸਺஋ͷ଍͠ࢉΛ૝ఆ࣮ͯ͠૷ͨ͠ͷʹɺ

    ར༻ऀ͸͜ͷؔ਺Λจࣈྻͷ࿈݁ͷͨΊͩͱޡղͯ͠͠·ͬͨ
    ʂ

    View Slide

  10. ҙࢥૄ௨ͷϛε
    w ίʔ
    υΛॻ͍͍ͯΔ্Ͱͷϛε͸UZQPɺ
    ͏
    ͔ͬΓ࡟আͳͲ༷ʑ
    w ։ൃऀಉ࢜ͷҙࢥૄ௨͕ίʔ
    υ্Ͱ׬݁͠ͳ͍͜ͱ΋

    ҙࢥૄ௨ͷϛεͱݺ΂Α
    ͏
    w จࣈྻ࿈݁ؔ਺ͱޡղͯ͠͠·ͬͨ։ൃऀ͸ɺ

    add()ؔ਺͕Ͳ͏͍͏ؔ਺ͳͷ͔࣮૷ऀຊਓʹฉ͘
    ·Ͱ೺ѲͰ͖ͳ͔ͬͨ

    View Slide

  11. ଞਓͷίʔ
    υɺ
    ਖ਼͠
    ͘ղऍͯ͠ಡΜͰ·͔͢
    ʁ
    w ΋ͪΖΜ͜Ε͸͘͢͝ۃ୺ͳྫ

    ʢ+ ͸਺஋ͷՃࢉʹͷΈ༻͍ͯɺ
    จࣈྻ࿈݁͸ String#join() ΍5FNQMBUFMJUFSBMTΛ࢖͏ํ͕Α
    Γ਌੾ʣ

    w ͔͠͠ɺ
    ۀ຿͸͜͏͍ͬͨ
    ʮଞਓͷίʔ
    υΛᴥᴪͳ͘ղऍͰ͖͍ͯΔ͔ʯ
    ͱ͍͏

    ධՁͷ࿈ଓͰ͋Δ
    w ίʔ
    υதͷ৘ใྔ͕๡͍͠ͱɺ
    ͨͱ͑1BSTBCMFͳίʔ
    υͰ͋ͬͨͱͯ͠΋

    ଞͷ։ൃऀͷҙਤ·Ͱղऍ͢Δͷ͸೉͍͠

    View Slide

  12. ܕΞϊςʔγϣϯ
    function add(a: number, b: number): number {


    return a + b;


    }
    5ZQF4DSJQUͰ͸ɺ
    Ҿ਺΍໭Γ஋ͷܕΛදه͢Δ

    ͜ΕΛܕΞϊςʔγϣϯ 5ZQFBOOPUBUJPOT
    ͱ͍͏

    View Slide

  13. ܕΞϊςʔγϣϯ
    function add(a: number, b: number): number {


    return a + b;


    }
    ܕΞϊςʔγϣϯͷ͓͔͛Ͱɺ
    5ZQF4DSJQUίϯύΠ
    ϥ͚ͩͰͳ͘

    ίʔ
    υΛಡΉਓؒʹ΋ҙਤΛղऍ͢Δखॿ͚ͱͳΔ
    ʮ͋ɺ
    ͜Ε͸number͔ͩΒจࣈྻ࿈݁ʹ࢖͏ؔ਺͡Όͳ͍ͳ
    ʂ
    ʯ

    View Slide

  14. ʜͱ͍͏࿩͸೥લޙʹࢄʑ͞Ε·
    ͨ͠

    View Slide

  15. ೥͸ܕΞϊςʔγϣϯॻ͍ͯ·͢ΑͶ
    w ͕͢͞ʹ5ZQF4DSJQU΋όʔδϣϯYʹಥೖ͠੒ख़͖ͯͨ͠
    w पΓͰॻ͍͍ͯΔ։ൃऀ΋͔ͳΓ૿͑ͨ
    w --noImplicitAny --noImplicitReturns ͳͲͷ

    UTDPO
    fi
    H$PNQJMFS0QUJPOTͷ͓͔͛Ͱ

    Ξϊςʔγϣϯͷॻ͖࿙ΕΛ๷͙ํ๏΋௕೥ཱ֬͞Ε͍ͯΔ

    View Slide

  16. ܕΞϊςʔγϣϯ͸Έͳ͞Μॻ͍͍ͯΔͱࢥ͍·͢ͷͰɺ

    ͜Ε͔Β͸
    ʮཁ݅Ξϊςʔγϣϯʯ
    Λॻ͍ͯΈ·ͤΜ͔

    View Slide

  17. ཁ݅Ξϊςʔγϣϯ
    ʁ
    w ຊߘͷ଄ޠ
    w ͪΐͬͱΩϟονʔͳλΠ
    τϧʹ͔͚ͨͬͨͩ͠ͳͷͰ

    άάͬͯ΋ެࣜͷ
    υΩϡϝϯ
    τͱ͔͸ग़͖ͯ·ͤΜ
    w ܕΞϊςʔγϣϯʹܕҎ্ͷ৘ใྔΛ΋ͨͤΔ͜ͱͰ

    ೝࣝͷᴥᴪΛΑ
    Γແ͘
    ͢͜ͱΛ໨తͱ͢Δͷ͕ຊ࣭

    View Slide

  18. ͜
    ͏͍͏
    ͜ͱɺ
    ͨ͜͠ͱ͋Δਓ
    type UserId = string;


    type BookId = string;
    ຊΛ؅ཧ͢ΔΞϓϦ

    UserId΋BookId΋จࣈྻͳΜ͚ͩͲ۠ผ͍ͨ͠ʜ

    View Slide

  19. type UserId = string;


    type BookId = string;


    async function fetchBook(id: BookId): Promise {


    //


    }


    export function BookCard(): JSX.Element {


    const [book, setBook] = useState(null);


    useEffect(() => {


    (async (): Promise => {


    const result = await fetchBook();


    setBook(result);


    })();


    }, []);


    return <>>;


    }
    ͜Μͳঢ়گ͕͋ͬͨͱ͠·͠ΐ
    ͏

    View Slide

  20. type UserId = string;


    type BookId = string;


    async function fetchBook(id: BookId): Promise {


    //


    }


    export function BookCard(): JSX.Element {


    const [book, setBook] = useState(null);


    useEffect(() => {


    (async (): Promise => {


    const result = await fetchBook();


    setBook(result);


    })();


    }, []);


    return <>>;


    }
    fetchBook()ؔ਺ʹ͸BookIdܕͷҾ਺Λ౉ͤ͹Αͦ͞͏
    Ͱ͢

    View Slide

  21. const id: BookId = 'ckyx69gli000009ju65mvhyw7';


    const result = await fetchBook(id);
    Αͦ͞͏

    View Slide

  22. const id: UserId = 'ckyx6c8xc000009jm8acefv2v';


    const result = await fetchBook(id);
    ຊ౰ʹ
    ʁ
    ʁ
    ʁ

    ίϯύΠϧ௨ͬͯΔΑ
    ʁ
    ʁ
    ʁ

    View Slide

  23. const result = await fetchBook('͜Μʹͪ͸');
    ͳΜͳΒ͜Ε΋௨Δ

    View Slide

  24. ίϯύΠ
    ϥ͸۠ผ͠·ͤΜ
    w typeΛ࢖ͬͯstringʹผ໊Λ͚ͭͯ΋

    ͦΕ͸͋͘
    ·Ͱ΋ΤΠ
    ϦΞε
    ʢผ໊ʣ
    ʹ͗͢ͳ͍
    w ͳͷͰυΩϡϝϯ
    τʹ΋ͪΌΜͱ5ZQF"MJBTFTͱॻ͔Ε͍ͯΔ

    https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-aliases

    w ਓؒʹ͸ผ໊Ͱ͋Δ͜ͱ͸ࣝผͰ͖Δ͕

    ίϯύΠ
    ϥʹ͸stringʹผ໊Λ෇͚ͨ͜ͱ͔͠఻Θ͍ͬͯͳ͍
    w UserIdͱBookId͕ޓ͍ʹstringͷผ໊Ͱ͋Δͱ͍͏͚ͩͰ

    ͦΕΒ͕ޓ͍ʹ۠ผ͞Ε͏
    Δ΂͖ͱ͍͏ཁ݅·Ͱ͸ίϯύΠ
    ϥʹ఻Θ͍ͬͯͳ͍

    View Slide

  25. ͳΒ͹Ϋϥε͔
    ʁ
    class UserId {


    constructor(public readonly value: string) {}


    }


    class BookId {


    constructor(public readonly value: string) {}


    }
    UserIdͱBookIdΛͦΕͧΕclassͰએݴͯ͠Έͨ

    View Slide

  26. const id = new BookId('ckyx69gli000009ju65mvhyw7');


    const result = await fetchBook(id);
    ͕͢͞ʹࠓ౓͸Αͦ͞͏
    ʁ

    View Slide

  27. const id = new UserId('ckyx6c8xc000009jm8acefv2v');


    const result = await fetchBook(id);
    ͩΊͰ͢

    ͜Ε΋ίϯύΠϧ͕௨Δ

    View Slide

  28. 5ZQF4DSJQU͸4USVDUVSBM5ZQJOHͰ͋Δ
    w 5ZQF4DSJQU͸ܕͷผ໊Ͱ۠ผͨ͠Γɺ
    Ϋϥε໊͕ҟͳΔ͜ͱͰ۠ผ͢ΔͷͰ͸ͳ͘

    ৗʹ
    ʮϓϩύςΟͷߏ੒ʯ
    ʹΑͬͯܕͷ۠ผΛ͚ͭΔ
    w ͜͏͍ͬͨܕͷ൑ผํࣜΛ4USVDUVSBM5ZQJOHͱ͍͏
    w ͜Ε͸υΩϡϝϯ
    τʹ΋هࡌ͞Ε͍ͯΔ

    https://www.typescriptlang.org/docs/handbook/type-compatibility.html

    w ܕ໊ͷҧ͍͚ͩͰܕ͕ҟͳ͍ͬͯΔͱ൑ผ͢Δํࣜ͸/PNJOBM5ZQJOHͱ͍͏
    w 5ZQF4DSJQU͸ͪ͜Βͷํࣜ͸࠾༻͍ͯ͠ͳ͍

    View Slide

  29. ϓϩύςΟͷҰக
    class UserId {


    constructor(public readonly value: string) {}


    }


    class BookId {


    constructor(public readonly value: string) {}


    }
    valueͱ͍͏
    ϓϩύςΟ͕ݸ͋ΔΫϥε

    ͱ͍͏఺Ͱɺ
    ߏ଄͕Ұக͍ͯ͠Δ

    Αͬͯ4USVDUVSBM5ZQJOHʹج͍ͮͯ͜ΕΒ͸ಉҰܕͱΈͳ͞ΕΔ

    View Slide

  30. ϓϩύςΟ
    ΛҰகͤ͞ͳ͍Α
    ͏ʹ͢Δ
    class UserId {


    userId: unknown;


    constructor(public readonly value: string) {}


    }


    class BookId {


    bookId: unknown;


    constructor(public readonly value: string) {}


    }
    ͦΕͧΕͷΫϥεʹҟͳΔ໊લͷμϛʔϓϩύςΟ
    Λ଍͢͜ͱͰ

    ߏ଄͕Ұக͠ͳ͍Α
    ͏ʹͨ͠

    View Slide

  31. const id = new UserId('ckyx6c8xc000009jm8acefv2v');


    const result = await fetchBook(id);
    Argument of type 'UserId' is not assignable to parameter of type 'BookId'.


    Property 'bookId' is missing in type 'UserId' but required in type 'BookId'.(2345)
    Τϥʔʹͳͬͯ
    ͘Εͨ

    View Slide

  32. ʜͱ͍͏࿩͸೥ʹ͠·
    ͨ͠

    View Slide

  33. ʜͱ͍͏࿩͸೥ʹ͠·
    ͨ͠
    5ZQF4DSJQUಋೖͰಘΒΕΔ
    ʮม͍͑ͯ͘༐ؾʯ

    https://speakerdeck.com/okunokentaro/the-courage-to-change-by-typescript

    View Slide

  34. Ϋϥε๏͸Կ͕Πέͯͳ͍͔
    w 5ZQF4DSJQUͰΫϥεશൠΛ࢖͏
    ͜ͱͷੋඇΛड़΂ΔΘ͚Ͱ͸ͳ͍
    w /PNJOBM5ZQJOH
    ʮͬΆ͍ʯ
    ͜ͱΛ͢ΔͨΊʹΫϥεΛಋೖ͢Δͷ͸Πέͯͳ͍
    w ͳ͔ͥ
    ʁ

    View Slide

  35. const id = new UserId('ckyx6c8xc000009jm8acefv2v');


    await fetch(`https://something/api/users/${id}`);
    5FNQMBUFMJUFSBMTʹͯ
    ͜ͷΑ
    ͏ʹύεʹ*%ؚ͕·ΕΔΑ
    ͏ͳ63-͸Α
    ͘
    ͋Δ

    ݁Ռ͸
    ʁ

    View Slide

  36. https://something/api/users/[object Object]
    👆 👆 👆 👆
    👇 👇👇 👇
    👇

    View Slide

  37. Ϧςϥϧͱ
    ͯ͠ѻ͑ͳ͍
    w new UserId()͍ͯ͠ΔͨΊɺ
    ݁Ռ͸typeof id === 'object'ͱͳΔ
    w จࣈྻϦςϥϧͰ͸ͳ͘ɺ
    valueΛϓϩύςΟ
    ͱ
    ͯ࣋ͭ͠ΦϒδΣΫ
    τʹͳΔ
    w toString()Λ࣮૷͢Ε͹[object Object]͸ճආͰ͖Δ͕

    ͜ͷख๏Λࢼ͢ࡍʹຖճͦͷ࣮૷͕ඞཁ
    w μϛʔϓϩύςΟ
    Λੜ΍͞ͳ͖ΌࣝผͰ͖ͳ͍ͷ΋ඇຊ࣭త
    w Ϧςϥϧͷ··ѻ͑ͯɺ
    ͔ͭ/PNJOBM5ZQJOHͬΆ͍ܕ൑ผΛ͢Δʹ͸ʜ
    ʁ

    View Slide

  38. ྩ࿨࠷৽൛

    View Slide

  39. UZQF/PNJOBM
    w type NominalΛએݴ͢Δ
    w { __brand: U }ͱ͍͏ΦϒδΣΫ
    τͱͷަࠩܕ &
    ʹ͢Δ͜ͱͰϦςϥϧͷ··
    ۠ผͰ͖ΔΑ
    ͏ʹ͢Δ
    w ਖ਼֬ͳग़య͸ൃݟͰ͖͍ͯͳ͍͕ෳ਺ͷจݙ͋Γ
    w #SBOEFE5ZQFTͱ΋ݺ͹Ε͍ͯΔ͕

    ʮ/PNJOBM5ZQJOHΛ࣮ݱ͍ͨ͠ͷ͔ͩΒʯ
    ͱ͍͏҆௚ͳ೔ຊਓతޠ๏Ͱ

    ࠓճ͸Nominalͱͨ͠
    export type Nominal = T &
    { __brand: U };

    View Slide

  40. /PNJOBMܕΛ࢖ͬͯ࠶௅ઓ
    type Nominal = T & { __brand: U };


    type BookId = Nominal;


    type UserId = Nominal;


    const id = 'ckyx6c8xc000009jm8acefv2v' as UserId;


    const result = await fetchBook(id);
    Argument of type 'UserId' is not assignable to parameter of type 'BookId'.


    Type 'UserId' is not assignable to type '{ __brand: "BookId"; }'.


    Types of property '__brand' are incompatible.


    Type '"UserId"' is not assignable to type '"BookId"'.(2345)
    ͪΌΜͱ۠ผͰ͖͍ͯΔ

    View Slide

  41. type Nominal = T & { __brand: U };


    type BookId = Nominal;


    type UserId = Nominal;


    const id = 'ckyx6c8xc000009jm8acefv2v' as UserId;


    const result = await fetchBook(id);
    ʮͰ΋BTېࢭͯ͠·ͤΜͰͨ͠
    ʁ
    ʯ

    View Slide

  42. લճͷ͓͞Β͍
    https://speakerdeck.com/okunokentaro/techstand6
    Ԟ໺ݡଠ࿠͸લճͷ5ZQF4DSJQUొஃʹͯBTΛېࢭ͍ͯͨ͠
    ʂ
    ʂ
    ʂ

    View Slide

  43. "TTFSUJPOGVODUJPOTΛ࢖͏
    Α
    ͏ʹ͢Δ
    w ͜ͷख๏Ͱ͸ΧδϡΞϧʹas͕ग़͖ͯͯ͠·͍
    ʮBTېࢭʯ
    ʹ൓ͯ͠͠·
    ͏
    w ͦͷͨΊɺ
    Nominalܕͷ஋Ͱ͋Δͱ͍ࣔͨ͠৔߹͸ඞͣ

    5ZQFQSFEJDBUFTɺ
    ·ͨ͸"TTFSUJPOGVODUJPOTΛ࢖͏
    Α
    ͏ʹ͢Δ

    View Slide

  44. BTTFSU4USJOH
    ؔ਺Λ࡞ͬͯΈΔ
    export function isString(v: unknown): v is string {


    return typeof v === 'string';


    }


    export function assertString(v: unknown, target = ''): asserts v is string {


    if (!isString(v)) {


    throw new Error(`${target} should be string`.trim());


    }


    }
    ౰ͨΓલͷΑ
    ͏ͳ಺༰ͷؔ਺͕ͩɺ

    unknownܕΛstringܕͱΈͳͨ͢Ίʹ͸ɺ
    Θ͟Θ͟͜͏͍ͬͨؔ਺͕ඞཁ

    View Slide

  45. /PNJOBMܕͱ"TTFSUJPOGVODUJPOTͷԠ༻
    import { isString } from './assert-string';


    import { Nominal } from './nominal';


    type FilledString = Nominal;


    function isFilledString(v: unknown): v is string {


    return isString(v) && v !== '';


    }


    function assertFilledString(


    v: unknown,


    target = ''


    ): asserts v is FilledString {


    if (!isFilledString(v)) {


    throw new Error(`${target} should be not empty string`.trim());


    }


    }
    type FilledStringΛએݴ͠ɺ
    ඞۭͣจࣈྻͰ͸ͳ͍͜ͱΛද໌͢Δ

    View Slide

  46. /PNJOBMܕͷෳ߹
    import { FilledString, assertFilledString } from '../utils/filled-string';


    import { Nominal } from '../utils/nominal';


    export type UserId = Nominal;


    function assertUserId(v: unknown): asserts v is UserId {


    assertFilledString(v);


    }


    export function asUserId(v: unknown): UserId {


    assertUserId(v);


    return v;


    }
    ͞Βʹɺ
    FilledStringܕΛຬͨ͢൑ผՄೳܕͱͯ͠type UserIdΛએݴ͢Δɻ

    ಉख๏Ͱએݴ͢Δtype BookIdͱίϯύΠ
    ϥ͕۠ผͰ͖Δ্ʹ

    ۭจࣈؚ͕·Εಘͳ͍͜ͱ΋อূࡁΈ
    ʂ

    ʢ"TTFSUJPOGVODUJPOʹ͸ࣗಈςε
    τͷ࣮ࢪ͕ඞਢʣ

    View Slide

  47. Ԡ༻ͷՄೳੑ͸ແݶେ
    w ͜ͷख๏Λ׆༻͢Δͱ
    Ϧςϥϧͷදݱͷ෯͕޿͕Δ
    w ྫ͑͹ʜ
    w ۭจࣈྻΛېࢭ͢Δ6TFS*Eܕ
    w ಛఆͷਖ਼نදݱΛຬ͍ͨͯ͠ͳ͍ͱΤϥʔͱͳΔ'PSNFEܕ
    w খ਺஋΍/B/ΛೝΊͳ͍6OJY5JNFܕ
    w ۠ผՄೳͳ4FDPOEܕͱ.JMMJTFDPOEܕ
    w ͳͲͳͲ

    View Slide

  48. ܕΞϊςʔγϣϯ͸
    ʮܕ͔͠Θ͔Βͳ͍ʯ
    w fetchBook(id: string)Ͱ͸

    ͳΜΒ͔ͷจࣈྻΛҾ਺ʹͱΔ͜ͱ
    ͔͠Θ͔Βͳ͍
    w ͦΕ͸UserId͔΋͠Εͳ͍͠ɺ
    ۭจࣈྻΛ౉ͯ͠΋͍͍͔΋͠Εͳ͍
    w ܕΞϊςʔγϣϯ͔Β͸
    ʮstringܕͷ஋Ͱ͋Δ͜ͱʯ
    Ҏ֎ͳʹ΋Θ͔Βͳ͍
    w ೥લͷ+BWB4DSJQUˠ5ZQF4DSJQUͷ࣌୅͸ɺ
    ͜ΕͰ΋ཱ೿ͳ΋Μͩͬͨ

    View Slide

  49. ܕΞϊςʔγϣϯʹؚΊΔ৘ใྔΛ૿΍͢
    w type BookId = NominalΛએݴ͓ͯ͘͠
    ͱ

    fetchBook(id: BookId)ͱ͍͏γάωνϟ͔ΒಘΒΕΔ৘ใྔ͕

    fetchBook(id: string)ʹൺ΂͙ͯͬͱ૿͢
    w ͦΕ͸UserIdͰ͸μϝͱΘ͔Δ
    w ͦΕ͸ۭจࣈྻͰ͸μϝͱΘ͔Δ
    w ࣮૷୲౰ऀʹޱ಄Ͱฉ͍ͯճΔඞཁ͕ͳ͍
    w ͜ͷߟ͑ํ͸ܖ໿ϓϩάϥϛϯά
    ʢ%FTJHOCZ$POUSBDU %C$ͳͲͱ΋ʣ
    ͷ

    ํ๏࿦ʹج͍͍ͮͯΔ
    w ಛʹࣄલ৚݅΍ෆม৚݅ʹ֘౰

    View Slide

  50. த਎ͷ͋ΔΞϊςʔγϣϯ΁
    w ཁ݅ΛܕΞϊςʔγϣϯʹؚΊΔʕʕཁ݅Ξϊςʔγϣϯʹ͢Δ͜ͱͰ

    ߦͷίʔ
    υ͔ΒಡΈखʹ఻ΘΔҙਤ͕Α
    Γ๛͔ʹͳΔ
    w ͜Ε·Ͱͷ೥͸+BWB4DSJQU͔Β5ZQF4DSJQU΁ͷա౉ظͩͬͨ
    w ͜Ε͔Β͸ίʔ
    υ͕5ZQF4DSJQUͱͯ͠ɺ
    5ZQF4DSJQUΒ͘͠੒ख़͍ͯ࣌͘͠୅
    w 5ZQF4DSJQUͱ
    ͯ͠Α
    Γ๛͔ͳදݱΛ͢ΔͳΒ

    த਎ͷͳ͍ΞϊςʔγϣϯΑ
    Γத਎ͷ͋ΔΞϊςʔγϣϯΛ৺͕͚ΔͱΑ͍

    View Slide

  51. 5IBOLZPV
    https://commons.wikimedia.org/wiki/File:IRS46_nasa.jpg

    View Slide