この記事は新歓ブログリレー2023の38日目の記事です。
こんにちは。mehm8128です。
今回はtype challengesをやってみた話を書きます。
僕はtraPでは主にフロントエンドをやっていて、TypeScriptというプログラミング言語を書くことが多いのですが、type challengesとはそのプログラミング言語の型を使ったパズルのようなものです。
以下のリンクからみなさんも遊ぶことができます(環境構築等は不要です)。
https://github.com/type-challenges/type-challenges
type challengesで使うTypeScriptの知識はここらへん↓をある程度知っていれば大丈夫だと思います(もちろん調べながら解くのもOKです)。
https://typescriptbook.jp/reference
1問解いてみる
「2 Get Return Type」を実際に解いてみます(ネタバレなので解きたい方は先に自分で解いて下さい)。
ここで問題、解答ページへのリンク、他の人の解答等が見れます。
https://github.com/type-challenges/type-challenges/blob/main/questions/00002-medium-return-type/README.md
解答画面は以下のようになっていて、Your Code Here
と書いてあるところを修正して解答を作ります
TypeScriptにはReturnType
というユーティリティ型があり、関数の型を入れるとその返り値の型を返してくれます。
ReturnType: https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype
それをここでは自分で実装してみなさいって言ってるんですね。
ということで書いたコードがこんな感じです
Test Cases
のところは多分最初の段階だと赤線がたくさん引かれていると思うのですが、正しい解答を書くと赤線が全部消えるので、ここで合っているかどうかの判別が大体できます。
今回使っているものをリストアップします
- extends: https://typescriptbook.jp/reference/generics/type-parameter-constraint
- conditional types: https://www.typescriptlang.org/docs/handbook/2/conditional-types.html
- 3項演算子の型バージョンです
- infer: https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#inferring-within-conditional-types
- ここにGetReturnTypeの実装も書いてありますね
- 残余引数: https://typescriptbook.jp/reference/functions/rest-parameters
- 型を書かないバージョンはJavaScriptにもあります
簡単に解説すると、渡された型T
が(...args: any[]) => U
(任意の関数)の形をしているときに、MyReturnType<T>
はU
になって、それ以外のときはnever
になる、という感じのコードです。
TypeScriptの型で遊んでる記事は↓のようなものも過去に投稿されているので、読んでみてください!
実際にコード書くときに使えるんですか
実際にコード書くときも、ユーティリティ型をわざわざ再実装することは無くても、上で出てきたような知識を使ったり、ユーティリティ型を使って型をごちゃごちゃしていい感じにすることは割とあります。
いくつか例を紹介します。といってもコード読むのは難しいと思うので、使ってるんだなーって雰囲気だけ感じてもらえれば十分です。
Jomon
僕がたくさんコード書いてるtraPのプロジェクトです。
https://github.com/traPtitech/Jomon-UI/blob/main/src/lib/apiTypes.ts
サーバーから取得したデータのcreated_at等、時刻を表している部分をluxonのDateTime
型に変換しています。
extends
は上で説明したもので、Omit
はユーティリティ型です。
Omit: https://typescriptbook.jp/reference/type-reuse/utility-types/omit
traQ
僕がちょっとコード書いてるtraPのプロジェクトです。
https://github.com/traPtitech/traQ_S-UI/pull/3813/files
これはdependencyのアップデートが入った時に使っている関数の返り値の型が変わっちゃって型エラーが発生していたので修正したやつです。
//
storeToRefs
の返り値の型
というコメントがあったのでこれは先ほど登場したReturnType
の出番でしょと思って書き換えました。これで関数の返り値の型に変更があってもStoreToRefs
の型も自動で変わるようになりました。
ちなみに実際にはdependencyに変更があった元のコードを軽く読みに行って原因を探ったりもしています。
Pinia: https://github.com/vuejs/pinia/pull/1898
多分初登場のものはこれですかね。
typeof: https://typescriptbook.jp/reference/type-reuse/typeof-type-operator
SWR
僕がバグ報告のissueを立てて他の人が直してくれたやつです。
https://github.com/vercel/swr/pull/2452/files
なんか色々ありますね。実は最初は僕が自分で直そうとして数時間格闘したのですが、どう直せばいいか分からなくて諦めました。
まだ紹介していないもので出てきているのはここらへんでしょうか。
デフォルト型引数: https://typescriptbook.jp/reference/generics/default-type-parameter
Required: https://typescriptbook.jp/reference/type-reuse/utility-types/required
四則演算
https://asterisks.netlify.app/2021/05/01/ts-tuple-calc/
型だけを使って四則演算をしようとするヤクザがこの世にはいるらしいです。
確か僕も全部は読んでないのですが、前半だけでも読んでみると面白いと思います。
まとめ
ということで色々見てきましたが、実は僕もまだtype challengesは20問くらいしかやっていないので、暇なときに進めていこうと思います。
明日の担当はharu10くんです、お楽しみにー