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

TypeScript 4.9のas const satisfiesが便利

TypeScript 4.9のas const satisfiesが便利

今日開催の「TechFeed Experts Night#11 〜 JavaScript/TypeScript最前線」で発表した資料です。

https://techfeed.io/events/techfeed-experts-night-11

Zennの記事はこちら
https://zenn.dev/moneyforward/articles/typescript-as-const-satisfies

tonkotsuboy_com

January 18, 2023
Tweet

More Decks by tonkotsuboy_com

Other Decks in Programming

Transcript

  1. 5ZQF4DSJQUͷ BTDPOTUTBUJT fi FT͕ศར ϚωʔϑΥϫʔυࣛ໺૖ 5FDI'FFE&YQFSUT/JHIUʙ+BWB4DSJQU5ZQF4DSJQU࠷લઢ

  2. ࣛ໺૖[email protected] ϚωʔϑΥϫʔυϏδωεΧϯύχʔ 
 ܦཧࡒ຿ϓϩμΫτຊ෦ϓϩμΫτ։ൃ෦෭෦௕

  3. ࣥචɿ+BWB4DSJQUίʔυϨγϐू

  4. ࣥචɿ೔ܦιϑτ΢ΣΞ

  5. ࠓ೔఻͍͑ͨ͜ͱ

  6. BTDPOTUTBUJTGJFTΛ࢖͏ͱɺ XJEFOJOHͷ๷ࢭͱ ܕਪ࿦݁Ռͷอ͕࣋Ͱ͖Δ

  7. BTDPOTUTBUJTGJFT

  8. BTDPOTUTBUJTGJFT

  9. TBUJTGJFTͱ͸ʁ 01

  10. satisfiesͱ͸ 式 satisfies 型 w ͕ࣜܕʹϚον͢Δ͔Ͳ͏͔ʁΛνΣοΫ͢Δ w 5ZQF4DSJQUͰಋೖ͞Εͨ IUUQTEFWCMPHTNJDSPTPGUDPNUZQFTDSJQUBOOPVODJOHUZQFTDSJQU

  11. satisfiesͷൃԻɾҙຯ ൃԻ w αςΟεϑΝΠζʢˈT‘UɪˌTGBɪ[ʣ ҙຯ w ຬ଍ͤ͞Δɺຬͨ͢ w TBUJTGZʹࡾ୯ݱͷT͕͍ͭͨܗ

  12. satisfiesͷಈ࡞ ಲࠎେֶ͕TUSJOHܕʹϚον͢Δ͔Ͳ͏͔ʁ0, ͕TUSJOHܕʹϚον͢Δ͔Ͳ͏͔ʁ/( const foo = "豚⾻⼤学" satisfies string; const

    foo = 14 satisfies string;
  13. satisfiesͷಈ࡞ type Person = { age: number name: string }

    const myPerson = { age: 18, name: ["ラーメン", "うどん"] } satisfies Person; type Person = { age: number name: string } const myPerson = { age: 18, name: "千賀" } satisfies Person; OBNF͕TUSJOH͡Όͳ͍ͷͰ/( 0,
  14. 2ܕ஫ऍͱԿ͕ҧ͏ͷʁ🤔 "ਪ࿦݁ՌΛอ࣋͢Δ͔Ͳ͏͔

  15. ܕ஫ऍͱsatisfies type MyType = { foo: string; }; // 型注釈

    const object1: MyType = { foo: "HELLO", }; // satisfies const object2 = { foo: "HELLO", } satisfies MyType;
  16. ܕ஫ऍͷ৔߹ DPMPS-JTUHSFFO͸VOLOPXOͳͷͰɺ഑ྻͷNBQ ؔ਺͸࢖͑ͳ͍ type ColorList = { [key in "red"

    | "green" | "blue"]: unknown; }; const colorList: ColorList = { red: "#ff0000", green: [0, 255, 0], blue: "#00ffff", }; // unknownなのでNG colorList.green.map((value) => value * 2);
  17. satisfiesͷ৔߹ DPMPS-JTUHSFFO͸OVNCFS<>ʹਪ࿦͞ΕΔͷͰɺ഑ྻͷNBQ ؔ਺͕࢖͑Δ type ColorList = { [key in "red"

    | "green" | "blue"]: unknown; }; const colorList = { red: "#ff0000", green: [0, 255, 0], blue: "#00ffff", } satisfies ColorList; // number[]なのでOK colorList.green.map((value) => value * 2);
  18. TBUJTGJFT͸ɺܕνΣοΫ͠ͳ͕Β΋ ܕਪ࿦݁ՌΛอ࣋Ͱ͖Δ

  19. BTDPOTUΛ૊Έ߹ΘͤΔͱศར

  20. BTDPOTU 02

  21. BTDPOTUTBUJTGJFT

  22. as constͱ͸ ࣜBTDPOTU ࢀߟɿϓϩΛ໨ࢦ͢ਓͷͨΊͷ5ZQF4DSJQUೖ໳ʢٕज़ධ࿦ࣾʣCZ[email protected] • 5ZQF4DSJQUͰಋೖ • จࣈྻɾ਺஋ɾਅِ஋ͳͲͷϦςϥϧܕΛXJEFOJOH͠ͳ͍ • ΦϒδΣΫτ಺ͷ͢΂ͯͷϓϩύςΟ͕SFBEPOMZʹͳΔ

    • ഑ྻϦςϥϧͷਪ࿦݁Ռ͕λϓϧܕʹͳΔ
  23. widening: Ϧςϥϧܕ͕ϓϦϛςΟϒܕʹ֦େ // "ラーメン"型 const food: "ラーメン" = "ラーメン"; //

    「20」型 const age: 20 = 20; // 推論結果は"⽥中"型 const name = "⽥中"; // 推論結果はtrue型 const isValid = true; ϓϦϛςΟϒܕ // string型 const food: string = "ラーメン"; // number型 const age: number = age; // 推論結果はstring型 let name = "⽥中"; Ϧςϥϧܕ
  24. wideningͷى͜Δέʔε // nameの推論結果は"⽥中"型 const name = "⽥中"; // name2の推論結果はstring型 let

    name2 = name; OBNF͸ాதܕ͕ͩɺOBNF͸TUSJOHܕʹXJEFOJOH͞ΕΔ
  25. ഑ྻͷwidening // 推論結果は string[] const myArray = [ "ラーメン", "うどん",

    "梅が枝餅" ]; // 値の書き換えができる myArray[0] = "モツ鍋"; NZ"SSBZ͸<ϥʔϝϯ ͏ͲΜ ക͕ࢬṷ>Ͱ͸ͳ͘ɺTUSJOH<>ʹਪ࿦͞ΕΔ
  26. ΦϒδΣΫτͷwidening // 推論結果 {age: number, name: string} const myObject =

    { age: 18, name: "⽥中", }; // 値の書き換えができる myObject.age = 30; NZ0CKFDU͸\BHF OBNFాத^Ͱ͸ͳ͘ɺ 
 \BHFOVNCFS OBNFTUSJOH^ʹਪ࿦͞ΕΔ
  27. BTDPOTUΛ͔ͭ͏ͱ XJEFOJOHͷ๷ࢭ SFBEPOMZԽ͕Ͱ͖Δ

  28. wideningͷ๷ࢭ // nameの推論結果は"⽥中"型 const name = "⽥中" as const; //

    name2の推論結果も"⽥中"型 let name2 = name; MFUએݴͨ͠OBNF΋ాதܕʹͳΔ
  29. ഑ྻͷwidening๷ࢭ + readonlyԽ // 推論結果は // ["ラーメン", "うどん", "梅が枝餅"] const

    myArray = [ "ラーメン", "うどん", "梅が枝餅" ] as const; // 書き換え不可能 myArray[0] = "モツ鍋"; NZ"SSBZ͸λϓϧͷ <ϥʔϝϯ ͏ͲΜ ക͕ࢬṷ>ʹਪ࿦͞ΕΔ
  30. ΦϒδΣΫτͷwidening๷ࢭ // 推論結果は {age: 18, name: "⽥中"} const myObject =

    { age: 18, name: "⽥中", } as const; // 書き換え不可能 myObject.age = 30; NZ0CKFDU͸\BHF OBNFాத^ʹਪ࿦͞ΕΔ
  31. ఆ਺ΛFYQPSU͢Δͱ͖͸ ඇXJEFOJOH SFBEPOMZͷ৔߹͕ଟ͍ͷͰ ੵۃతʹBTDPTOUΛ͚ͭΔ͜ͱ͕ଟ͍

  32. BTDPOTUͱTBUJTGJFTΛ૊Έ߹ΘͤΔ 03

  33. as constͱsatisfiesͷ૊Έ߹Θͤ as const satisfies XJEFOJOH๷ࢭ  SFBEPOMZԽ ˓ ʷ

    ܕνΣοΫ ʷ ˓
  34. as constͱsatisfiesͷ૊Έ߹Θͤ as const satisfies as const satisfies XJEFOJOH๷ࢭ 

    SFBEPOMZԽ ˓ ʷ ˓ ܕνΣοΫ ʷ ˓ ˓
  35. BTDPOTUTBUJTGJFTͷαϯϓϧ

  36. as const satisfiesͷαϯϓϧ type Person = { age: number; name:

    string; tags: string[]; }; 1FSTPOܕʹϚον͢ΔΦϒδΣΫτΛ࡞Δ
  37. BTDPOTUͳ͠ˠXJEFOJOH๷ࢭ❌ TBUJT fi FTͳ͠ˠܕνΣοΫ❌ type Person = { age: number;

    name: string; }; export const myPerson = { age: "⼆⼗歳", name: "⽥中", };
  38. BTDPOTUͳ͠ˠXJEFOJOH๷ࢭ❌ TBUJT fi FTͳ͠ˠܕνΣοΫ❌ OVNCFSܕ͕ೖΔ΂͖͕ͩɺ ܕνΣοΫͰ͖͍ͯͳ͍👎 *%&ͷਪ࿦݁Ռදࣔɻ XJEFOJOH͍ͯ͠Δ👎 type Person

    = { age: number; name: string; }; export const myPerson = { age: "⼆⼗歳", name: "⽥中", };
  39. BTDPOTU͋ΓˠXJEFOJOH๷ࢭ⭕ TBUJT fi FTͳ͠ˠܕνΣοΫ❌ type Person = { age: number;

    name: string; }; export const myPerson = { age: "⼆⼗歳", name: "⽥中", } as const;
  40. BTDPOTU͋ΓˠXJEFOJOH๷ࢭ⭕ TBUJT fi FTͳ͠ˠܕνΣοΫ❌ *%&ͷਪ࿦݁Ռදࣔɻ XJEFOJOH๷ࢭ SFBEPOMZ👍 type Person =

    { age: number; name: string; }; export const myPerson = { age: "⼆⼗歳", name: "⽥中", } as const; OVNCFSܕ͕ೖΔ΂͖͕ͩɺ ܕνΣοΫͰ͖͍ͯͳ͍👎
  41. BTDPOTUͳ͠ˠXJEFOJOH๷ࢭ❌ TBUJT fi FT͋ΓˠܕνΣοΫ⭕ type Person = { age: number;

    name: string; }; export const myPerson = { age: "⼆⼗歳", name: "⽥中", } satisfies Person;
  42. type Person = { age: number; name: string; }; export

    const myPerson = { age: "⼆⼗歳", name: "⽥中", } satisfies Person; BTDPOTUͳ͠ˠXJEFOJOH๷ࢭ❌ TBUJT fi FT͋ΓˠܕνΣοΫ⭕ *%&ͷਪ࿦݁Ռදࣔɻ XJEFOJOH͍ͯ͠Δ👎 OVNCFSܕ͕ೖΔ΂͖ՕॴΛ ܕνΣοΫ͍ͯ͠Δ👍
  43. BTDPOTU͋ΓˠXJEFOJOH๷ࢭ⭕ TBUJT fi FT͋ΓˠܕνΣοΫ⭕ type Person = { age: number;

    name: string; }; export const myPerson = { age: "⼆⼗歳", name: "⽥中", } as const satisfies Person;
  44. type Person = { age: number; name: string; }; export

    const myPerson = { age: "⼆⼗歳", name: "⽥中", } as const satisfies Person; BTDPOTU͋ΓˠXJEFOJOH๷ࢭ⭕ TBUJT fi FT͋ΓˠܕνΣοΫ⭕ *%&ͷਪ࿦݁Ռදࣔɻ XJEFOJOH๷ࢭ SFBEPOMZ👍 OVNCFSܕ͕ೖΔ΂͖ՕॴΛ ܕνΣοΫ͍ͯ͠Δ👍
  45. BTDPOTU͋ΓˠXJEFOJOH๷ࢭ⭕ TBUJT fi FT͋ΓˠܕνΣοΫ⭕ type Person = { age: number;

    name: string; }; export const myPerson = { age: 20, name: "⽥中", } as const satisfies Person; मਖ਼ͨ͠ΦϒδΣΫτͰͷ *%&ਪ࿦݁Ռ
  46. ίʔυͰͷ׆༻ྫ

  47. ΞϓϦέʔγϣϯͷόʔδϣϯ؅ཧఆ਺ export const appVersion = "1.0.2" as const satisfies `${number}.${number}.${number}`;

  48. URLͷҰཡΛ؅ཧ export const urlList = { apple: "https://www.apple.com/jp/", google: "https://www.google.com/",

    yahoo: "https://www.yahoo.co.jp/", } as const satisfies { // 値は https:// で始まるURLに限定する [key: string]: `https://${string}`; };
  49. Χϥʔίʔυͷྻڍ export const color = { apple: "#65AB51", black: "#000",

    // 中略 white: "#FFFFFF", whiteSmoke: "#F7F7F7", } as const satisfies { [key: string]: `#${string}`; };
  50. εςʔλεͷ഑ྻ export const statusList = [ { status: "processing", title:

    "作業中" }, { status: "cancel", title: "キャンセル" }, { status: "completed", title: "完了" }, ] as const satisfies readonly { status: string; title: string; }[];
  51. ઃఆϑΝΠϧ export const config = { target: "es2021", cache: {

    type: "filesystem", }, output: { asyncChunks: true, folder: "dist", }, } as const satisfies MyConfig;
  52. ·ͱΊ

  53. BTDPOTUTBUJTGJFTͰ XJEFOJOH๷ࢭͱ ܕਪ࿦݁Ռͷอ͕࣋Ͱ͖Δ

  54. ͱ͘ʹɺఆ਺ΛFYQPSU͢Δ৔߹͸ ࢖͏ਓͷ͜ͱΛߟ͑ͯ BTDPOTUTBUJTGJFT͓ͯ͜͠͏

  55. هࣄͰ΋ৄ͘͠ղઆ͍ͯ͠·͢ IUUQT[FOOEFWNPOFZGPSXBSEBSUJDMFTUZQFTDSJQUBTDPOTUTBUJT fi FT

  56. Thank y ! @tonkotsuboy_com @matsu_eri 5XJUUFSͰ͸࠷৽ϑϩϯτΤϯυٕज़Λൃ৴͍ͯ͠·͢