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࠷લઢ

    View full-size slide

  2. ࣛ໺૖!UPOLPUTVCPZ@DPN
    ϚωʔϑΥϫʔυϏδωεΧϯύχʔ

    ܦཧࡒ຿ϓϩμΫτຊ෦ϓϩμΫτ։ൃ෦෭෦௕

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  5. ࠓ೔఻͍͑ͨ͜ͱ

    View full-size slide

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

    View full-size slide

  7. BTDPOTUTBUJTGJFT

    View full-size slide

  8. BTDPOTUTBUJTGJFT

    View full-size slide

  9. TBUJTGJFTͱ͸ʁ
    01

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  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,

    View full-size slide

  14. 2ܕ஫ऍͱԿ͕ҧ͏ͷʁ🤔
    "ਪ࿦݁ՌΛอ࣋͢Δ͔Ͳ͏͔

    View full-size slide

  15. ܕ஫ऍͱsatisfies
    type MyType = {


    foo: string;


    };


    // 型注釈


    const object1: MyType = {


    foo: "HELLO",


    };


    // satisfies


    const object2 = {


    foo: "HELLO",


    } satisfies MyType;

    View full-size slide

  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);

    View full-size slide

  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);

    View full-size slide

  18. TBUJTGJFT͸ɺܕνΣοΫ͠ͳ͕Β΋
    ܕਪ࿦݁ՌΛอ࣋Ͱ͖Δ

    View full-size slide

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

    View full-size slide

  20. BTDPOTUTBUJTGJFT

    View full-size slide

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

    View full-size slide

  22. 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 = "⽥中";
    Ϧςϥϧܕ

    View full-size slide

  23. wideningͷى͜Δέʔε
    // nameの推論結果は"⽥中"型


    const name = "⽥中";


    // name2の推論結果はstring型


    let name2 = name;
    OBNF͸ాதܕ͕ͩɺOBNF͸TUSJOHܕʹXJEFOJOH͞ΕΔ

    View full-size slide

  24. ഑ྻͷwidening
    // 推論結果は string[]


    const myArray = [


    "ラーメン",


    "うどん",


    "梅が枝餅"


    ];


    // 値の書き換えができる


    myArray[0] = "モツ鍋";
    NZ"SSBZ͸<ϥʔϝϯ ͏ͲΜ ക͕ࢬṷ>Ͱ͸ͳ͘ɺTUSJOH<>ʹਪ࿦͞ΕΔ

    View full-size slide

  25. ΦϒδΣΫτͷwidening
    // 推論結果 {age: number, name: string}


    const myObject = {


    age: 18,


    name: "⽥中",


    };


    // 値の書き換えができる


    myObject.age = 30;
    NZ0CKFDU͸\BHF OBNFాத^Ͱ͸ͳ͘ɺ

    \BHFOVNCFS OBNFTUSJOH^ʹਪ࿦͞ΕΔ

    View full-size slide

  26. BTDPOTUΛ͔ͭ͏ͱ
    XJEFOJOHͷ๷ࢭSFBEPOMZԽ͕Ͱ͖Δ

    View full-size slide

  27. wideningͷ๷ࢭ
    // nameの推論結果は"⽥中"型


    const name = "⽥中" as const;


    // name2の推論結果も"⽥中"型


    let name2 = name;
    MFUએݴͨ͠OBNF΋ాதܕʹͳΔ

    View full-size slide

  28. ഑ྻͷwidening๷ࢭ + readonlyԽ
    // 推論結果は


    // ["ラーメン", "うどん", "梅が枝餅"]


    const myArray = [


    "ラーメン",


    "うどん",


    "梅が枝餅"


    ] as const;


    // 書き換え不可能


    myArray[0] = "モツ鍋";
    NZ"SSBZ͸λϓϧͷ
    <ϥʔϝϯ ͏ͲΜ ക͕ࢬṷ>ʹਪ࿦͞ΕΔ

    View full-size slide

  29. ΦϒδΣΫτͷwidening๷ࢭ
    // 推論結果は {age: 18, name: "⽥中"}


    const myObject = {


    age: 18,


    name: "⽥中",


    } as const;


    // 書き換え不可能


    myObject.age = 30;
    NZ0CKFDU͸\BHF OBNFాத^ʹਪ࿦͞ΕΔ

    View full-size slide

  30. ఆ਺ΛFYQPSU͢Δͱ͖͸
    ඇXJEFOJOHSFBEPOMZͷ৔߹͕ଟ͍ͷͰ
    ੵۃతʹBTDPTOUΛ͚ͭΔ͜ͱ͕ଟ͍

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  34. BTDPOTUTBUJTGJFTͷαϯϓϧ

    View full-size slide

  35. as const satisfiesͷαϯϓϧ
    type Person = {


    age: number;


    name: string;


    tags: string[];


    };
    1FSTPOܕʹϚον͢ΔΦϒδΣΫτΛ࡞Δ

    View full-size slide

  36. BTDPOTUͳ͠ˠXJEFOJOH๷ࢭ❌
    TBUJT
    fi
    FTͳ͠ˠܕνΣοΫ❌
    type Person = {


    age: number;


    name: string;


    };


    export const myPerson = {


    age: "⼆⼗歳",


    name: "⽥中",


    };

    View full-size slide

  37. BTDPOTUͳ͠ˠXJEFOJOH๷ࢭ❌
    TBUJT
    fi
    FTͳ͠ˠܕνΣοΫ❌
    OVNCFSܕ͕ೖΔ΂͖͕ͩɺ
    ܕνΣοΫͰ͖͍ͯͳ͍👎
    *%&ͷਪ࿦݁Ռදࣔɻ
    XJEFOJOH͍ͯ͠Δ👎
    type Person = {


    age: number;


    name: string;


    };


    export const myPerson = {


    age: "⼆⼗歳",


    name: "⽥中",


    };

    View full-size slide

  38. BTDPOTU͋ΓˠXJEFOJOH๷ࢭ⭕
    TBUJT
    fi
    FTͳ͠ˠܕνΣοΫ❌
    type Person = {


    age: number;


    name: string;


    };


    export const myPerson = {


    age: "⼆⼗歳",


    name: "⽥中",


    } as const;

    View full-size slide

  39. BTDPOTU͋ΓˠXJEFOJOH๷ࢭ⭕
    TBUJT
    fi
    FTͳ͠ˠܕνΣοΫ❌
    *%&ͷਪ࿦݁Ռදࣔɻ
    XJEFOJOH๷ࢭSFBEPOMZ👍
    type Person = {


    age: number;


    name: string;


    };


    export const myPerson = {


    age: "⼆⼗歳",


    name: "⽥中",


    } as const;
    OVNCFSܕ͕ೖΔ΂͖͕ͩɺ
    ܕνΣοΫͰ͖͍ͯͳ͍👎

    View full-size slide

  40. BTDPOTUͳ͠ˠXJEFOJOH๷ࢭ❌
    TBUJT
    fi
    FT͋ΓˠܕνΣοΫ⭕
    type Person = {


    age: number;


    name: string;


    };


    export const myPerson = {


    age: "⼆⼗歳",


    name: "⽥中",


    } satisfies Person;

    View full-size slide

  41. type Person = {


    age: number;


    name: string;


    };


    export const myPerson = {


    age: "⼆⼗歳",


    name: "⽥中",


    } satisfies Person;
    BTDPOTUͳ͠ˠXJEFOJOH๷ࢭ❌
    TBUJT
    fi
    FT͋ΓˠܕνΣοΫ⭕
    *%&ͷਪ࿦݁Ռදࣔɻ
    XJEFOJOH͍ͯ͠Δ👎
    OVNCFSܕ͕ೖΔ΂͖ՕॴΛ
    ܕνΣοΫ͍ͯ͠Δ👍

    View full-size slide

  42. BTDPOTU͋ΓˠXJEFOJOH๷ࢭ⭕
    TBUJT
    fi
    FT͋ΓˠܕνΣοΫ⭕
    type Person = {


    age: number;


    name: string;


    };


    export const myPerson = {


    age: "⼆⼗歳",


    name: "⽥中",


    } as const satisfies Person;

    View full-size slide

  43. type Person = {


    age: number;


    name: string;


    };


    export const myPerson = {


    age: "⼆⼗歳",


    name: "⽥中",


    } as const satisfies Person;
    BTDPOTU͋ΓˠXJEFOJOH๷ࢭ⭕
    TBUJT
    fi
    FT͋ΓˠܕνΣοΫ⭕
    *%&ͷਪ࿦݁Ռදࣔɻ
    XJEFOJOH๷ࢭSFBEPOMZ👍
    OVNCFSܕ͕ೖΔ΂͖ՕॴΛ
    ܕνΣοΫ͍ͯ͠Δ👍

    View full-size slide

  44. BTDPOTU͋ΓˠXJEFOJOH๷ࢭ⭕
    TBUJT
    fi
    FT͋ΓˠܕνΣοΫ⭕
    type Person = {


    age: number;


    name: string;


    };


    export const myPerson = {


    age: 20,


    name: "⽥中",


    } as const satisfies Person;
    मਖ਼ͨ͠ΦϒδΣΫτͰͷ
    *%&ਪ࿦݁Ռ

    View full-size slide

  45. ίʔυͰͷ׆༻ྫ

    View full-size slide

  46. ΞϓϦέʔγϣϯͷόʔδϣϯ؅ཧఆ਺
    export const appVersion =


    "1.0.2" as const satisfies `${number}.${number}.${number}`;

    View full-size slide

  47. 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}`;


    };

    View full-size slide

  48. Χϥʔίʔυͷྻڍ
    export const color = {


    apple: "#65AB51",


    black: "#000",


    // 中略


    white: "#FFFFFF",


    whiteSmoke: "#F7F7F7",


    } as const satisfies {


    [key: string]: `#${string}`;


    };

    View full-size slide

  49. εςʔλεͷ഑ྻ
    export const statusList = [


    { status: "processing", title: "作業中" },


    { status: "cancel", title: "キャンセル" },


    { status: "completed", title: "完了" },


    ] as const satisfies readonly {


    status: string;


    title: string;


    }[];

    View full-size slide

  50. ઃఆϑΝΠϧ
    export const config = {


    target: "es2021",


    cache: {


    type: "filesystem",


    },


    output: {


    asyncChunks: true,


    folder: "dist",


    },


    } as const satisfies MyConfig;

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide