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כ㸜Ⰻ䚍׾锃眍〳腉 •

    㸜Ⰻ䚍׾♴־׷ --noImplicitAnyך搀⸬⻉ anyas@ts-ignoreזו • 㸜Ⰻ䚍׾♳־׷ VOJPO㘗װ勴⟝㘗זוך崞欽 • 㸜Ⰻ䚍׾넝׭׷קו؝أز׮♳傻 㘗ػؤٕ׾װ׶ֺׅ׷ה؝أػָ䝤⻉
  2. 㘗ך؝أزػؿؓ٦وٝأ 㸜Ⰻ䚍 㘗ך׋׭ך 㷕统؝أز Ꟛ涪؝أز 넝 搀 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 } 㸜Ⰻ䚍搀 !
  3. 㘗ך؝أزػؿؓ٦وٝأ 㸜Ⰻ䚍 㘗ך׋׭ך 㷕统؝أز Ꟛ涪؝أز 넝 搀 const items: Record<string,

    { price: 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 } 㸜Ⰻ䚍⚥ ! !
  4. 㘗ך؝أزػؿؓ٦وٝأ 㸜Ⰻ䚍 㘗ך׋׭ך 㷕统؝أز Ꟛ涪؝أز 넝 搀 type ItemName =

    'apple' | 'orange' const assertIsItemPriceData = <D extends Record<ItemName, { price: number; taxRate?: number }>>(data: D) => data const items = assertIsItemPriceData({ apple: { price: 128 }, orange: { price: 200, taxRate: 1.1 } }) type Distribute<N extends ItemName> = N extends ItemName ? ((typeof items)[N] extends { taxRate: number } ? (name: N) => number : (name: N, taxRate: number) => number) : never type UtoI<U> = (U extends any ? (arg: U) => void : never) extends (arg: infer I) => void ? I : never type getPriceIncludingTaxFunc = UtoI<Distribute<ItemName>> const getPriceIncludingTax: getPriceIncludingTaxFunc = ( name: ItemName, taxRate?: number ) => { const item = items[name] as any taxRate = (taxRate || item.taxRate) as number return item.price * taxRate } 㸜Ⰻ䚍넝 ! !
  5. 5ZQF4DSJQUך㸜Ⰻ䚍ה؝أز 㸜Ⰻ䚍 㘗ך׋׭ך 㷕统؝أز Ꟛ涪؝أز 넝 搀 غٓٝأ׾罋ִ״ֲ • 㸜Ⰻ䚍ָו׸ֻ׵ְ妜׃ְךַ

    וך玎䏝ך⽬ꤹ䚍׾鏩㺁ׅ׷ךַ • ؝أز׾ו׸ֻ׵ְ䩪ִ׷ךַ • 剑穄湡垥כוֿזךַ 䖓ַ׵54׾㼪Ⰵׅ׷㜥さ
  6. 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㘗׾侧⦼װ俑㶵⴨ה׃ג 䪔׏ג׮ؒٓ٦חז׵זְ
  7. 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ך鄃㹱 儗꟦䊴余䷼
  8. 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ؒٓ٦׾涪欰ׇׁ׷挿׮⳷䝤
  9. BTח״׷㘗ٍؗأزך⢽  const v = getNumberOrString() as string; console.log(v.slice(0, 10));

    function getNumberOrString(): number | string { return Math.random() ? "foo" : 123; } number | string㘗ך䒭׾ string㘗חتٍؐٝؗأز
  10. 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ך鄃㹱㹋遤儗ؒٓ٦
  11. BTך䕦갟眔㔲 const v = getNumberOrString() as string; console.log(v.slice(0, 10)); function

    getNumberOrString(): number | string { return Math.random() ? "foo" : 123; } ㎳ָ㢌侧ח⥂㶷ׁ׸׋ ךד׉׸⟃꣬Ⰻגָ ㎳ך䕦갟眔㔲ח
  12. 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; }
  13. 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ח⥜姻 ؒحآ؛٦أ׾ꤐֽל姻׃ְ
  14. 㢌侧ח㎳׾⥂㶷׃זְ 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; }
  15. 㢌侧ח㎳׾⥂㶷׃זְ 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, ֿֿכ姻׃ְ
  16. ꟼ侧ך؎ٝة٦ؿؑ٦أד㎳׾אַזְ interface Foo { type: 'foo' } function isFoo(obj: any):

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

    obj is Foo { return obj != null && obj.type === 'foo' } BOZך䕦갟眔㔲כꟼ侧ⰻⰋג ꟼ侧Ⰻ⡤ך姻׃ׁ׾➂꟦ָ ⥂鏾ׅ׸ל0, ˟勴⟝㘗זו׾ꟼ侧ך㘗ח⢪ֲ㜥さ׮㣐⡤ֿ׸חז׷勴⟝㘗כ䱿锷דֹזְךד