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

はじめに

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

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

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

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

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