ちゃなべの備忘録

ほぼ備忘録です。

TypeChallengeをやった_Easy編【備忘録】

はじめに

型パズルをやった備忘録を残しまする

環境整え

これ入れた。

marketplace.visualstudio.com

あとはフォルダ指定して、やるだけ。

解いた

4-Pick (Easy)

問題

組み込みの型ユーティリティPick<T, K>を使用せず、TからKのプロパティを抽出する型を実装します。

例えば:

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

type TodoPreview = MyPick<Todo, 'title' | 'completed'>

const todo: TodoPreview = {
    title: 'Clean room',
    completed: false,
}
思考

ふむふむ。どうやるんやろ。

なんか、& 使えそうだけど、全然わからん。

ブルベリ本見てたら使えそうなやつあった。それがmapped types。これ使ってみるか。

そして、T型から型を取得すればいい。

あとは型引数の部分型を指定してやる。

↓こうなった。

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

んでこれは正解っぽい。

7-Readonly (Easy)

問題

組み込みの型ユーティリティReadonly<T>を使用せず、T のすべてのプロパティを読み取り専用にする型を実装します。実装された型のプロパティは再割り当てできません。

例えば:

interface Todo {
  title: string
  description: string
}

const todo: MyReadonly<Todo> = {
  title: "Hey",
  description: "foobar"
}

todo.title = "Hello" // Error: cannot reassign a readonly property
todo.description = "barFoo" // Error: cannot reassign a readonly property
思考

さっきの問題と似てるくね?またmapped types使う。

そして、あとはreadonlyつけるだけかな。

readonlyはkey名の前につけるの注意。

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

11-Tuple to Object (Easy)

問題

タプルを受け取り、その各値のkey/valueを持つオブジェクトの型に変換する型を実装します。

例えば:

const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const

type result = TupleToObject<typeof tuple> // expected { 'tesla': 'tesla', 'model 3': 'model 3', 'model X': 'model X', 'model Y': 'model Y'}
思考

さっきから同じ感じじゃない? これもmapped typesよな。

そしてーーー、mapped typeのkey部分({ [P in K]: T }のK部分)にはユニオン型が必要。

なので、タプル→ユニオンに変換できれば良い。 調べたら、Tuple[number]ってやれば良さそう。

type TupleToObject<T extends readonly (string | number | symbol)[]> = {
  [TKey in T[number]]: TKey
}

11-Tuple to Object (Easy)

問題

配列Tを受け取り、その最初のプロパティの型を返すFirst<T>を実装します。

例えば:

type arr1 = ['a', 'b', 'c']
type arr2 = [3, 2, 1]

type head1 = First<arr1> // expected to be 'a'
type head2 = First<arr2> // expected to be 3
思考

ほう。これはーーーtypeofの出番か? でもなさそう。普通にこの記述してみたけど、中身が入ってない時はneverを返せって言われる。

type First<T extends any[]> = T[0]

じゃあconditional types使って中身がない時はnever返しますか?(半ギレ)明示的に。 あーーだとしても型引数の配列の長さを知りたいな。lengthプロパティの取り方を調べて。

type First<T extends any[]> = T["length"] extends 0 ? never : T[0]

なんかneverのパターンをconditional types 使うのがちょっと綺麗じゃないけどいいんかな。

解答見たけどconditional types使ってたな。てか T extends []っていう使い方おもろすぎ。あと可変長タプル型使うやつ。

18-Length of Tuple (Easy)

問題

タプルTを受け取り、そのタプルの長さを返す型Length<T>を実装します。

例えば:

type tesla = ['tesla', 'model 3', 'model X', 'model Y']
type spaceX = ['FALCON 9', 'FALCON HEAVY', 'DRAGON', 'STARSHIP', 'HUMAN SPACEFLIGHT']

type teslaLength = Length<tesla>  // expected 4
type spaceXLength = Length<spaceX> // expected 5
思考

だからさっきやったって。 ↓で終わり。lengthプロパティを呼び出す。

type Length<T extends readonly any[]> = T['length']

43-Exclude (Easy)

問題

組み込みの型ユーティリティExclude <T, U>を使用せず、Uに割り当て可能な型をTから除外する型を実装します。

例えば:

type Result = MyExclude<'a' | 'b' | 'c', 'a'> // 'b' | 'c'
思考

たぶん、mapped types とconditional typesを組み合わせるんかな?いや違うか。

最終的にユニオン型で返さないといけないよな、ユニオン型の引き算ってなんやねん。まぁそれがExcludeの本質なんだけど。

含むかどうかはextendsとかでわかるけど。

...すまん、わからんかった。

(答えを見る時間)

そんな使い方できるのーーー!conditional types。

記事みてみた。

qiita.com

ほえーー覚えとこう。

189-Awaited (Easy)

問題

Promise ライクな型が内包する型をどのように取得すればよいでしょうか。

例えば:Promise<ExampleType>という型がある場合、どのようにして ExampleType を取得すればよいでしょうか。

type ExampleType = Promise<string>

type Result = MyAwaited<ExampleType> // string
思考

これだめだ、たぶんガチで知らないやつ。試行錯誤が無駄なやつ、だって知らないとわからない問題ぽいから。

だから答え見るわ

(答えを見る時間)

へーーーー!!! infer便利やなぁ。これあれば、<>に囲まれた型を取得できるなぁ。

あと PromiseLike。Promiseのオブジェクトの条件がthenが入っていること。だけなのは衝撃。

268-If (Easy)

問題

条件値CCが truthy である場合の戻り値の型TCが falsy である場合の戻り値の型Fを受け取るIfを実装します。 条件値Ctruefalseのどちらかであることが期待されますが、TF は任意の型をとることができます。

例えば:

type A = If<true, 'a', 'b'>; // expected to be 'a'
type B = If<false, 'a', 'b'>; // expected to be 'b'
思考

肌感、めっちゃ余裕じゃね?conditional types使えば良さそう。

type If<C extends boolean, T, F> = C extends true ? T : F

え、解けたw

533-Concat (Easy)

問題

JavaScriptArray.concat関数を型システムに実装します。この型は 2 つの引数を受け取り、受け取ったイテレータの要素を順に含む新しい配列を返します。

例えば:

type Result = Concat<[1], [2]>; // expected to be [1, 2]
思考

んーー?すげぇ実装っぽいけどこれ型システムだけでできるんだ?? まぁあれか、タプル型を返すからいいのか、あくまで型だもんな。

当て勘で↓を書いてみたら当たった。ほぼ実装やん。

type Concat<T extends readonly any[], U extends readonly any[]> = [...T, ...U]

898-Includes (Easy)

問題

JavaScriptArray.include関数を型システムに実装します。この型は、2 つの引数を受け取り、truefalseを出力しなければなりません。

例えば:

type isPillarMen = Includes<['Kars', 'Esidisi', 'Wamuu', 'Santana'], 'Dio'> // expected to be `false`
思考

うーん、condditional typesなのはそうじゃないか。 あとは、タプル型でもらったのをユニオン型にして部分型か判断?

んでこうなった↓ だけどこれ不正解ね

type Includes<T extends readonly any[], U> = U extends T[number] ? true : false;

わかんねーー正解を見る。

(正解見てる)

めっちゃなるほど。infer使うのか。いやーーーinferいいな。 inferとconditional typesの合わせ技めっちゃ便利やん。

3057-Push (Easy)

問題

Array.pushジェネリックバージョンを実装します。

例えば:

type Result = Push<[1, 2], '3'> // [1, 2, '3']
思考

なんかーーinferでいけそうだな。 やってみるか、、いけた。

type Push<T extends any[], U> = T extends [...infer Rest] ? [...Rest, U] : never

んーーけど、infer使いたいがためにconditional typesやっているだけで、neverは定義しなくていいんだよな。 答えも見てみるか。

www そりゃそうだわwww

type Push<T extends unknown[], U> = [...T, U]

3060-Unshift (Easy)

問題

Array.unshiftの型バージョンを実装します。

例えば:

type Result = Unshift<[1, 2], 0> // [0, 1, 2,]
思考

...なめすぎでは? ほぼ前問と同じ。

type Unshift<T extends unknown[], U> = [U, ...T]

3312-Parameters (Easy)

問題

組み込みの型ユーティリティParameters<T>を使用せず、Tからタプル型を構築する型を実装します。

例えば:

const foo = (arg1: string, arg2: number): void => {}

type FunctionParamsType = MyParameters<typeof foo> // [arg1: string, arg2: number]
思考

これもinferでいけそう。 やってみるか、、、いけた。なんなんinfer

type MyParameters<T extends (...args: any[]) => any> = T extends (...args: infer Args) => any ? [...Args] : false

解答見てみたら、そもそも展開する必要なかったわ。 そうなのか、タプル型になるのか、inferは。

おわりに

よしーーーEasyモードは終わり。 次はMedium編。