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

最強の型を目指して ~TSのConditional Typesを理解する~

最強の型を目指して ~TSのConditional Typesを理解する~

D497c45a1fb82c383c62ef994a7c0fdc?s=128

SHUN/しゅん

March 08, 2021
Tweet

Transcript

  1. 最強の型を⽬指して ~TSのConditional Typesを理解する~ 1

  2. ⾃⼰紹介 名前: SHUN/しゅん 学年: ⾼専新3年⽣ 得意⾔語: TypeScript、JavaScript、Haskell、など 得意分野: Webがチョットデキル、TSの型芸、CI/CD Twitter:

    @shun_shobon GitHub: @shun-shobon 2
  3. 今⽇話すこと 3

  4. TypeScriptの型はすごい 4

  5. とはいえ 5

  6. TypeScriptの型は難しい 6

  7. 三⼤TSの難しい型 Mapped types Conditional types Template literal types 7

  8. 今回はこれらの中でも特に***†やばい†***Conditional typesを理解しようというコンセプトです 8

  9. 事前準備 さっきの2つの型を話す前にTSならではの型について解説します Union types Literal types なお、これから話すTSのサンプルコードはすべてTSの設定を strict: true (厳密な型チェ

    ックを有効にする)にしているものとします 9
  10. Union types ⽇本語では共⽤体型とか⾔われるやつ 複数の型の「どちらかを取りうる型」を定義することができる let value: string | number =

    123; console.log(value * 5); // Error! if (typeof value === "number") { console.log(value * 5); // OK! } value = "foo"; // OK! value = true; // Error! 10
  11. Literal types 値そのものを型として⽤いることができる type Foo = "foo" | "bar"; let

    foo: Foo = "foo"; // OK! foo = "bar"; // OK! foo = "baz"; // Error! 11
  12. 事前準備終了 12

  13. 本題 13

  14. Conditional types ⼀⾔でいうと、「型レベルif」 構⽂は T extends U ? V :

    W 「TがUに代⼊可能ならばVを、そうでなければWという型になる」⇒三項演算⼦みたいなもん TSで⼀番やべえ型 type Foo = "foo"; type Bar = Foo extends string ? "true" : "false"; const bar: Bar = "true"; // OK! const baz: Bar = "false"; // Error! 14
  15. え?これだけ? 15

  16. そんなことはない 16

  17. Type inference in Conditional types ジェネリクスに存在しない型を作り出せる機能 T extends U ?

    V : W のUの部分に infer X と書くことで、 V の部分で新たに作り出し た X を使⽤することができる type ArrayItem<T> = T extends Array<infer U> ? U : never; type Foo = Array<string>; type Bar = ArrayItem<Foo>; // string になる 17
  18. 例 Next.jsで⽤いられる動的ルーティングされる箇所のみをUnion Typesとして抽出 type QueryUnion<TPath extends string, TQueries extends string

    = never> = TPath extends `/[${infer Query}]/${infer Other}` ? QueryUnion<`/${Other}`, TQueries | Query> : TPath extends `/${infer _}/${infer Other}` ? QueryUnion<`/${Other}`, TQueries> : TPath extends `/[${infer Query}]` ? TQueries | Query : TPath extends `/${infer _}` ? TQueries : never; const path = "/[foo]/bar/[baz]/qux"; type Queries = QueryUnion<typeof path>; // => "foo" | "bar" 18
  19. 例 TSの型のみで作られたもの Brainf**k ⾃然数演算 SQL⽂パーサ GraphQL⽂パーサ 19

  20. こんな難しい型なんて使いこなせない… 20

  21. パズル感覚で学習できたら楽しくない? 21

  22. Type Challenge TSの様々な型機能を駆使して、出されたお題に対して最適な答えを探す 例: Union typesからTuple typesを作る、再帰を⽤いてObject typeのすべてをReadonly にするDeepReadonlyを作る、カリー化を型レベルでする、C⾔語のprintfっぽいものを 型レベルで作るなど

    答え合わせはテストケースを⽤いて⾃動でやってくれます 公式から正しい答えが提供されるわけではないので他の⼈の答えも⾒て、⾃分だけの答 えを探そう! 22
  23. まとめ 型芸は楽しいのでみんなもやろう! 23