✏️

[新感覚パズルゲーム]type-challenges初級編へTry

2021/03/01に公開

はじめに

  • 昨日のKPTで激ムズtype-challengesについて盛り上がったので、今度はしっかり学びながら問題を解いていき、まとめていこうと思います。
    type-challenges

さっそく

warm up

問題1

  • 僕の解答↓
/* _____________ Your Code Here _____________ */
type HelloWorld = string // expected to be a string

/* _____________ Test Cases _____________ */
import { Equal, Expect, NotAny } from '@type-challenges/utils'

type cases = [
  Expect<NotAny<HelloWorld>>,
  Expect<Equal<HelloWorld, string>>
]

  • 解説
    ジェネリクスについて知っていれば、わかる問題かなという感じです。

ジェネリクスってなんやねん?

基本的に、型がある言語にはジェネリクスというものがよく存在しています。
これは、クラス、インターフェース、メソッドなどの型をパラメータとして定義することです。
もちろんTypeScriptにもジェネリクスがあります。

書き方としては、型名をHoge<S, T>のようにします。
名前のあとに<>で囲った変数の列を与えることで、型の定義の中でそれらを型の変数として使うことができるのです。

また、この問題だと<HelloWorld, string>このジェネリクスに対しEqualを取っているので、type HelloWorld = stringとしてやれば良い。

easy

Pick<T, K>

問題

  • 僕の解答
type MyPick<T, K extends keyof T> = {[k in K]: T[k] }

/* _____________ Test Cases _____________ */
import { Equal, Expect } from '@type-challenges/utils'

type cases = [
  Expect<Equal<Expected1, MyPick<Todo, 'title'>>>,
  Expect<Equal<Expected2, MyPick<Todo, 'title' | 'completed'>>>,
  MyPick<Todo, 'title' | 'completed' | 'invalid'>,
]

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

interface Expected1 {
  title: string
}

interface Expected2 {
  title: string
  completed: boolean
}

  • 解説
    注目すべき点としては、まずK extends keyof Tという部分ですかね。

これは、型引数Kは型引数Tの部分型でなければならないうえ、typeof演算子を用いているので、与えられた値の型を文字列で返した時の部分型ということになります。
{[k in K]: T[k] }については、まず右側の: T[k]について明記する。
これは、Tが{ title: string; description: string; completed: boolean; }の型であることを指す。
次に、Mapped typesである[k in K]を知っている必要がある。
Mapped typesとは、Kはstringにアサイン可能なtypeであればよく、Kに対する値はTというtypeになるという意味です。
参照: Mapped types

Readonly<T>

問題

  • 僕の解答
/* _____________ Your Code Here _____________ */

type MyReadonly<T> = { readonly [K in keyof T]: T[K] }


/* _____________ Test Cases _____________ */
import { Equal, Expect } from '@type-challenges/utils'

type cases = [
  Expect<Equal<MyReadonly<Todo1>, Readonly<Todo1>>>,
]

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

  • 解説

まず、[K in keyof T]: T[K]ここは良さそうですね。先ほどの問題と似ています。
さて、ではreadonly こいつですが、何をしているのかというと、これを付けることで、宣言されたプロパティは再代入できなくしています。constみたいなもの。
なので、テストケースを見た際にExpect<Equal<MyReadonly<Todo1>, Readonly<Todo1>>>となっていると思いますが、右側のReadonly<Todo1>でTodo1の型に対し、左側のMyReadonly<Todo1>では型の制約([K in keyof T、型引数Kは型引数Tの部分型でなければならないうえ、typeof演算子を用いているので、与えられた値の型を返した時の部分型)となっているので、付き合わせて時にイコールとなり、テストをクリアしていることになります。

おわりに

いや、難しすぎる。。easyじゃないって。。。
途中で諦めてごめんなさい。

Discussion