🐶

TypeScriptで型パズルを始めてみよう

2020/09/29に公開

はじめに

TypeScriptの高度な型システム学びたいけど

  • 何からやればいいのか
  • たまに使うけど忘れる

といった方におすすめのものを見つけました

社内LTで発表したものを編集した記事になります。

type-challenges

https://github.com/type-challenges/type-challenges

This project is aim to help you better understand how the type system works, writing your own utilities, or just having fun with the challenges.
このプロジェクトの目的は、型システムがどのように動作するかをよりよく理解したり、独自のユーティリティを書いたり、あるいはチャレンジを楽しんだりすることです。

詳しくはtype-challengesのREADMEか下記のqiitaをどうぞ
https://qiita.com/ryo2132/items/925b96838dd8cca7cebd

型パズルやってみよう

難易度順にいくつか用意されているので、easyから1つやってみることにします。

雑に問題を訳すと皆さんご存知?の Pick<T, K> 型を自分で書いてみようになります

https://github.com/type-challenges/type-challenges/blob/master/questions/4-easy-pick/README.md

Take the Challenge をクリックすると 問題が記載されたts playgroundが出てきます。

回答

Pickのおさらい


interface Todo {
  title: string
  description: string
  completed: boolean
}

type p = Pick<Todo, 'title'>
// pの型は↓になる
type p = {
    title: string;
}

回答↓

回答 TypeScript playgroundが開きます

説明

type MyPick<T, K extends keyof T> = {
  [p in K]: T[p]
}
K extends keyof T の説明

keyof Tで Tのunion Typeが取得できる

K extends keyof T は Kが keyof T 型でないと駄目なことを表している。

[P in K]: T[P] の説明

mapped typeと呼ばれる型です。
簡単に説明すると

{[P in K]: T[P]}という型の意味は、「K型の文字列Pに対して、型T[P]を持つプロパティPが存在するようなオブジェクトの型」

です。
難しいですね。

今回の場合だと


type MyPick<T, K extends keyof T> = {
  [p in K]: T[p]
}

type mp = MyPick<Todo, 'title'>

TがTodo型、K が Todo型のkeyの union type 'title' | 'completed' | 'description' となります。
つまり、 'title' | 'completed' | 'description' 型の文字列Pに対して、型 Todo['title' | 'completed' | 'description'] をもつプロパティPが存在するオブジェクトの型です。

参考
https://qiita.com/ryo2132/items/925b96838dd8cca7cebd
https://qiita.com/uhyo/items/e2fdef2d3236b9bfe74a#conditional-types

Discussion