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

安全性の極北から見るTypeScript

uhyo
October 02, 2019

 安全性の極北から見るTypeScript

TypeScript meetup #3の発表資料です。

uhyo

October 02, 2019
Tweet

More Decks by uhyo

Other Decks in Programming

Transcript

  1. 㸜Ⰻ䚍ך噰⻌ַ׵鋅׷
    5ZQF4DSJQU
    5ZQF4DSJQU.FFUVQ

    View Slide

  2. 荈䊹稱➜
    –ؿٗٝزؒٝسؒٝآص،倜⼼䎃湡!-*/&吳䒭⠓爡
    – 5ZQF4DSJQU娖䎃⼱ֻ׵ְ
    –2JJUB蔓➂5ZQF4DSJQUةؚDPOUSJCVUJPO侧⡘
    – ! չ5ZQF4DSJQUך㘗ⰅꟌպ
    – "չ侁⻌罏ך5ZQF4DSJQUպ
    – # չ5ZQF4DSJQUך㘗䱿锷鑫铡պ זו
    !VIZP@

    View Slide

  3. !ⴱ׭גך涫㠡"

    View Slide

  4. 5ZQF4DSJQU׾⢪ֲאך椚歋
    –㸜Ⰻ䚍 ˘ 㘗ؒٓ٦׾嗚⳿׃גغؚ׾劢搫ח꣇־׷
    –Ꟛ涪⸬桦˘ 㘗䞔㜠׾欽ְ׋酡㸣ד⸬桦״ֻꟚ涪דֹ׷
    㘗ָسًُؗٝزחז׷
    ˟5ZQF4DSJQUדכ؝٦س欰䧭ח㘗䞔㜠כ⢪׻׸זְ

    View Slide

  5. 5ZQF4DSJQU׾⢪ֲאך椚歋
    –㸜Ⰻ䚍 ˘ 㘗ؒٓ٦׾嗚⳿׃גغؚ׾劢搫ח꣇־׷
    –Ꟛ涪⸬桦˘ 㘗䞔㜠׾欽ְ׋酡㸣ד⸬桦״ֻꟚ涪דֹ׷
    㘗ָسًُؗٝزחז׷
    ˟5ZQF4DSJQUדכ؝٦س欰䧭ח㘗䞔㜠כ⢪׻׸זְ

    View Slide

  6. 5ZQF4DSJQUך㸜Ⰻ䚍ה؝أز
    㸜Ⰻ䚍
    㘗ך׋׭ך
    㷕统؝أز
    Ꟛ涪؝أز


    • 5ZQF4DSJQUכ㸜Ⰻ䚍׾锃眍〳腉
    • 㸜Ⰻ䚍׾♴־׷
    --noImplicitAnyך搀⸬⻉
    anyas@ts-ignoreזו
    • 㸜Ⰻ䚍׾♳־׷
    VOJPO㘗װ勴⟝㘗זוך崞欽
    • 㸜Ⰻ䚍׾넝׭׷קו؝أز׮♳傻
    㘗ػؤٕ׾װ׶ֺׅ׷ה؝أػָ䝤⻉

    View Slide

  7. 㘗ך؝أزػؿؓ٦وٝأ
    㸜Ⰻ䚍
    㘗ך׋׭ך
    㷕统؝أز
    Ꟛ涪؝أز


    const items = {
    apple: {
    price: 128,
    },
    orange: {
    price: 200,
    taxRate: 0.1
    }
    }
    const getPriceIncludingTax = (name, taxRate) => {
    const item = items[name]
    taxRate = taxRate || item.taxRate
    if (taxRate == null) throw new Error("OMG")
    return item.price * taxRate
    }
    㸜Ⰻ䚍搀
    !

    View Slide

  8. 㘗ך؝أزػؿؓ٦وٝأ
    㸜Ⰻ䚍
    㘗ך׋׭ך
    㷕统؝أز
    Ꟛ涪؝أز


    const items: Recordprice: number; taxRate?: number
    }> = {
    apple: {
    price: 128
    },
    orange: {
    price: 200,
    taxRate: 1.1
    }
    }
    const getPriceIncludingTax = (name: string, taxRate?:
    number) => {
    const item = items[name]
    taxRate = taxRate || item.taxRate
    if (taxRate == null) throw new Error("OMG")
    return item.price * taxRate
    }
    㸜Ⰻ䚍⚥
    !
    !

    View Slide

  9. 㘗ך؝أزػؿؓ٦وٝأ
    㸜Ⰻ䚍
    㘗ך׋׭ך
    㷕统؝أز
    Ꟛ涪؝أز


    type ItemName = 'apple' | 'orange'
    const assertIsItemPriceData = number }>>(data: D) => data
    const items = assertIsItemPriceData({
    apple: {
    price: 128
    },
    orange: {
    price: 200,
    taxRate: 1.1
    }
    })
    type Distribute = N extends ItemName
    ? ((typeof items)[N] extends { taxRate: number }
    ? (name: N) => number : (name: N, taxRate: number) => number)
    : never
    type UtoI = (U extends any ? (arg: U) => void : never)
    extends (arg: infer I) => void ? I : never
    type getPriceIncludingTaxFunc = UtoI>
    const getPriceIncludingTax: getPriceIncludingTaxFunc = (
    name: ItemName, taxRate?: number
    ) => {
    const item = items[name] as any
    taxRate = (taxRate || item.taxRate) as number
    return item.price * taxRate
    }
    㸜Ⰻ䚍넝
    !
    !

    View Slide

  10. 5ZQF4DSJQUך㸜Ⰻ䚍ה؝أز
    㸜Ⰻ䚍
    㘗ך׋׭ך
    㷕统؝أز
    Ꟛ涪؝أز


    غٓٝأ׾罋ִ״ֲ
    • 㸜Ⰻ䚍ָו׸ֻ׵ְ妜׃ְךַ
    וך玎䏝ך⽬ꤹ䚍׾鏩㺁ׅ׷ךַ
    • ؝أز׾ו׸ֻ׵ְ䩪ִ׷ךַ
    • 剑穄湡垥כוֿזךַ
    䖓ַ׵54׾㼪Ⰵׅ׷㜥さ

    View Slide

  11. 5ZQF4DSJQUך㸜Ⰻ䚍ה؝أز
    㸜Ⰻ䚍
    㘗ך׋׭ך
    㷕统؝أز
    Ꟛ涪؝أز


    !ֿךز٦ؙכֿֿדׅ

    View Slide

  12. 5IJT5BML
    㸜Ⰻ䚍ח噰䮶׶׃׋5ZQF4DSJQU錁׾䋒侄׃תׅ!
    –㸜Ⰻ䚍הךぢֹさְ倯
    –⡦ָ㸜Ⰻ䚍׾腘ַׅךַ
    –וך״ֲח㸜Ⰻ䚍׾㸚׷ךַ

    View Slide

  13. 㸜Ⰻ䚍ַ׵鋅׷5ZQF4DSJQU
    5ZQF4DSJQUכ⨳Ⰻ䚍ך瑎ָ㢳ְ
    –孡鯪ח㎳׾אֻֿהָדֹ׷anyװasזו
    –׉׮׉׮㘗ءأذي荈⡤ח׮瑎ָ֮׷
    ⵃ⤑䚍娖〷涸穗箮㹋鄲♳ך㉏겗ך׋׭
    DG5ZQF4DSJQUךVOTBGFז乼⡲תה׭ ˊ 2JJUB CZ!LHULS
    ˟⨳Ⰻ䚍 TPVOEOFTT
    㘗ثؑحؙ׾鸐׸ל㹋遤儗ח㘗ؒٓ٦ָ饯ֹזְ䚍颵

    View Slide

  14. 㸜Ⰻ䚍ַ׵鋅׷5ZQF4DSJQU
    5ZQF4DSJQUכ⨳Ⰻ䚍ך瑎ָ㢳ְ
    –孡鯪ח㎳׾אֻֿהָדֹ׷anyװasזו
    –׉׮׉׮㘗ءأذي荈⡤ח׮瑎ָ֮׷
    ⵃ⤑䚍娖〷涸穗箮㹋鄲♳ך㉏겗ך׋׭
    ⨳Ⰻ䚍ך瑎׾㝰ֺ㸜Ⰻ䚍׾㸚׷ךכ䧮ղך䕵湡!

    View Slide

  15. ⡭锑ז׈㸜Ⰻ䚍חֿ׌׻׷ךַ
    㘗ءأذيך䠐㄂הכ⨳Ⰻ䚍ך椚锷涸⥂鏾זךד
    㸜Ⰻ䚍׾灶㠨ׅ׷ה
    㘗ءأذيך䠐㄂ָ搀חז׷ַ׵
    ˟植㹋ך鎉铂׾⵸חׅ׷ה椚锷涸⥂鏾הְֲַךכ㣄暟铂זךדָׅ׉ֿכ噰䮶׶ח⯜ׄג⹞䒔׃גֻ׌ְׁ

    View Slide

  16. 㸜Ⰻ䚍׾㸚׷חכ
    㣐⾱⵱
    ㎳׾אַזְ㣐⾱⵱
    㘗ءأذيך瑎׾瑱ְ׋㜥さכⴽזךד׉ֿכⴽ鷿孡׾אֽת׃׳ֲ

    View Slide

  17. ⡦ָ㸜Ⰻ䚍׾腘ַׅךַ
    ֮׷ְכ䧮ղכוך״ֲח㎳׾אֻךַ

    View Slide

  18. BOZ㘗
    ! BOZ㘗ך暴䗙
    –BOZ㘗ך⦼כ⟣䠐ךⵃ欽ָ〳腉
    ⡦׾׃ג׮㘗ؒٓ٦ָ饯ֹזְ
    –BOZ㘗ך⦼ַ׵䖤׋ⴽך⦼׮BOZ㘗׾䭯א
    فٗػذ؍،ؙإأ٥ꟼ侧ㄎן⳿׃ך鵤׶⦼זו
    ⚠ BOZ㘗ך⽬ꤹ䚍
    –׮כװ㶷㖈荈⡤ָ㎳
    –㎳ָ⠗厩ׅ׷ BOZ寅厩
    ˟֮ה㘗䞔㜠ָ#חז׷ךד酡㸣׮⸬ֹתׇ׿

    View Slide

  19. BOZ寅厩☠
    const obj: any = doSomeMagic();
    const res = obj.hello.world();
    const num: number = obj;
    const str: string = obj;
    function doSomeMagic(){ /* empty */ }
    BOZ㘗ך㢌侧PCK׾⡲䧭
    BOZ㘗ך⦼כוֲ⢪׏ג׮
    ؒٓ٦חז׵זְ
    BOZ㘗׾侧⦼װ俑㶵⴨ה׃ג
    䪔׏ג׮ؒٓ٦חז׵זְ

    View Slide

  20. BOZ寅厩☠
    const obj: any = doSomeMagic();
    const res = obj.hello.world();
    const num: number = obj;
    const str: string = obj;
    function doSomeMagic(){ /* empty */ }
    ֿךPCK׏ג㢌侧כו׿ז괏ח
    ⢪׏ג׮ؒٓ٦חז׵זְ׃
    侧⦼ד׮֮׷׃俑㶵⴨ד׮֮
    ׷׿أ״XXXXXXXXXXXX
    㣐㎳
    寅厩ׁ׸׋㢌侧BOZ寅厩彁
    鵤׶⦼כBOZ㘗✳如寅厩
    BOZך鄃㹱
    儗꟦䊴余䷼

    View Slide

  21. BOZ寅厩☠
    const obj: any = doSomeMagic();
    const res = obj.hello.world();
    const num: number = obj;
    const str: string = obj;
    function doSomeMagic(){ /* empty */ }
    寅厩眔㔲
    BOZ㘗ך㢌侧ָ֮׷
    أ؝٦فⰋג
    BOZ׾ꅿ佝׃חׅ׷ה
    ꬊ䌢ח⽬ꤹ
    寅厩ׁ׸׋㢌侧BOZ寅厩彁
    ˟BOZכ鸬ꓲ涸חOP*NQMJDJU"OZؒٓ٦׾涪欰ׇׁ׷挿׮⳷䝤

    View Slide

  22. BTח״׷㘗ٍؗأز
    ! BTח״׷㘗ٍؗأزך堣腉
    –䒭ך㘗׾ⴽך㘗חتٍؐٝؗأزדֹ׷
    ˟㘗䞔㜠ָ㢌׻׷׌ֽկ㹋遤儗כ⡦׮饯ֹזְ
    ⚠ BTח״׷㘗ٍؗأزך⽬ꤹ䚍
    –㎳׾אְג׮؝ٝػ؎ٓח䙫׵׸זְ
    ˟as constכasؗ٦ٙ٦س׾⢪׏גְ׷ֽוⴽ暟ד㸜Ⰻזךדו׿ו׿⢪ְת׃׳ֲկ

    View Slide

  23. BTח״׷㘗ٍؗأزך⢽

    const v = getNumberOrString() as string;
    console.log(v.slice(0, 10));
    function getNumberOrString(): number | string
    {
    return Math.random() ? "foo" : 123;
    }
    number | string㘗ך䒭׾
    string㘗חتٍؐٝؗأز

    View Slide

  24. BTח״׷㘗ٍؗأزך⢽

    const v = getNumberOrString() as string;
    console.log(v.slice(0, 10));
    function getNumberOrString(): number | string
    {
    return Math.random() ? "foo" : 123;
    }
    鵤׶⦼OVNCFS]TUSJOHהַ
    鎉׏ג׷ֽווְֲׇא׮
    TUSJOHד׃׳XXXXXXXX
    㣐㎳
    BTך鄃㹱㹋遤儗ؒٓ٦

    View Slide

  25. BTך䕦갟眔㔲
    const v = getNumberOrString() as string;
    console.log(v.slice(0, 10));
    function getNumberOrString(): number | string
    {
    return Math.random() ? "foo" : 123;
    }
    ㎳ָ㢌侧ח⥂㶷ׁ׸׋
    ךד׉׸⟃꣬Ⰻגָ
    ㎳ך䕦갟眔㔲ח

    View Slide

  26. BTח״׷㘗ٍؗأزך⢽

    function getAnchorOfNode(node: HTMLElement): HTMLAnchorElement | null {
    let current: HTMLElement | null = node;
    while (current) {
    if (current.tagName === "A") {
    return current as HTMLAnchorElement;
    }
    current = current.parentNode as HTMLElement | null;
    }
    return null;
    }

    View Slide

  27. BTח״׷㘗ٍؗأزך⢽

    function getAnchorOfNode(node: HTMLElement): HTMLAnchorElement | null {
    let current: HTMLElement | null = node;
    while (current) {
    if (current.tagName === "A") {
    return current as HTMLAnchorElement;
    }
    current = current.parentNode as HTMLElement | null;
    }
    return null;
    } current.parentNodeך㘗׾
    Node & ParentNode | nullַ׵
    HTMLElement | nullח⥜姻
    ؒحآ؛٦أ׾ꤐֽל姻׃ְ

    View Slide

  28. BOZהBTךתה׭
    –姻׃ְ倯ぢח㘗׾⥜姻ׅ׷׋׭ח⢪ֲֶ
    –㎳׾㢌侧ח⥂㶷׃׋儗挿ד،ؐز
    –BOZכװלְ㎳ד׃ַ׮⠗厩ׅ׷

    View Slide

  29. וך״ֲח㸜Ⰻ䚍׾㸚׷ךַ

    View Slide

  30. 㸜Ⰻ䚍׾㸚׷倯岀
    㣐⾱⵱
    ㎳ח״׷寅厩眔㔲׾杞ֻׅ׷

    View Slide

  31. 㸜Ⰻ䚍׾㸚׷倯岀
    㣐⾱⵱
    ㎳ח״׷寅厩眔㔲׾杞ֻׅ׷
    ➂꟦ָ顑⟣׾䭯א眔㔲׾杞ֻׅ׷
    㢌侧ח㎳׾⥂㶷׃זְ
    ⽬ꤹ䚍׾䒭חꟗׄ鴥׭׷㢌侧ٖكٕך姻׃ׁ׾➂ָ䬐⥂
    ꟼ侧ך؎ٝة٦ؿؑ٦أד㎳׾אַזְ
    ⽬ꤹ䚍׾ꟼ侧ⰻחꟗׄ鴥׭׷ꟼ侧ٖكٕך姻׃ׁ׾➂ָ䬐⥂
    ׉׸ָ搀椚ז׵

    View Slide

  32. 㢌侧ח㎳׾⥂㶷׃זְ
    function getAnchorOfNode(node: HTMLElement): HTMLAnchorElement | null {
    let current: HTMLElement | null = node;
    while (current) {
    if (current.tagName === "A") {
    return current as HTMLAnchorElement;
    }
    current = current.parentNode as HTMLElement | null;
    }
    return null;
    }

    View Slide

  33. 㢌侧ח㎳׾⥂㶷׃זְ
    function getAnchorOfNode(node: HTMLElement): HTMLAnchorElement | null {
    let current: HTMLElement | null = node;
    while (current) {
    if (current.tagName === "A") {
    return current as HTMLAnchorElement;
    }
    current = current.parentNode as HTMLElement | null;
    }
    return null;
    } BTך⽬ꤹ䚍ך䕦갟眔㔲
    ֿך㘗䓼ⵖָ姻׃ְֿה׾➂꟦ָ⥂鏾ׅ׸ל0,
    ֿֿכ姻׃ְ

    View Slide

  34. ꟼ侧ך؎ٝة٦ؿؑ٦أד㎳׾אַזְ
    interface Foo {
    type: 'foo'
    }
    function isFoo(obj: any): obj is Foo {
    return obj != null && obj.type === 'foo'
    }
    ♷ִ׵׸׋⡦׵ַך⦼objָ
    Foo㘗ַוֲַⴻ㹀ׅ׷ꟼ侧

    View Slide

  35. ꟼ侧ך؎ٝة٦ؿؑ٦أד㎳׾אַזְ
    interface Foo {
    type: 'foo'
    }
    function isFoo(obj: any): obj is Foo {
    return obj != null && obj.type === 'foo'
    }
    BOZך䕦갟眔㔲כꟼ侧ⰻⰋג
    ꟼ侧Ⰻ⡤ך姻׃ׁ׾➂꟦ָ
    ⥂鏾ׅ׸ל0,
    ˟勴⟝㘗זו׾ꟼ侧ך㘗ח⢪ֲ㜥さ׮㣐⡤ֿ׸חז׷勴⟝㘗כ䱿锷דֹזְךד

    View Slide

  36. תה׭
    䧮ղך顑⟣׾剑㼭ח׃אא㸜Ⰻ䚍׾䖤׷׋׭חכ
    ㎳ח״׷寅厩眔㔲׾杞ֻׅ׷
    ׉׮׉׮㎳כז׷ץֻ鼘ֽ׷

    View Slide

  37. 'VSUIFS3FBEJOH
    –侁⻌罏ך5ZQF4DSJQUˊ 2JJUB CZ!VIZP
    –㸜Ⰻ䚍ך嚊䙀׾䓼ְ鎉衝ד铡ֻ鎸✲
    –BOZװBT⟃㢩ך⽬ꤹ䚍׮《׶䪔׏גְתׅ
    –׀㸜䗰ֻ׌ְׁծֿךز٦ؙךⰻ㺁׾㸚׸ל⹧ⵃ罏דׅ
    – 5ZQF4DSJQUךABTTFSUTYJT5A㘗כוך״ֲח⽬ꤹזךַ ˊ 2JJUB CZ!VIZP
    –顑⟣眔㔲׾杞ֻׅ׷הְֲ罋ִ倯׾ك٦أחِ٦ؠ٦㹀纏㘗鶢铂
    ך⢪ְ倯׾罋㻊׃׋鎸✲

    View Slide