Closed18

Type Challengesを解いていく(初級)

Yuki TerashimaYuki Terashima

ここから初級


Pick

Pick<T, K>とすれば当然のように通るが、それだとダメなやつ。

自分の解答
type MyPick<T, K> = { [P in K]: T[P] }

としたけど、ジェネリクスの方を修正しても良いことを失念していた。

良さそうな解答例

Yuki TerashimaYuki Terashima

Readonly

これまたReadonly<T>ではダメなやつ。

自分の解答
type MyReadonly<T> = { readonly [K in keyof T]: T[K] }

readonlyを付与する場所を間違え続けていた・・・。

Yuki TerashimaYuki Terashima

Tuple to Object

配列をユニオンにするやつ。

自分の解答
type TupleToObject<T extends readonly any[]> = { [K in T[number]]: K }

他の問題もそうだけど、知らないと解けない感が増している・・・。

あとany[]の箇所はstring[]などにしたほうが良さそうではある。

Yuki TerashimaYuki Terashima

First of Array

配列の最初の要素の型を取得。

自分の解答
type First<T extends any[]> = T[0] extends undefined ? never : T[0]

としたけど、これだと最後のテストケースが通らない。

配列に要素がないことを確認するためにはどうすればよいか?ということで、[][number]の型を確認し、これがneverになることがわかったため、以下のような解答にするとテストケースがすべて通った。

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

ただ、他の解答を確認してみたところ、T extends []T["length"] extends 0としており、この方が直感的だなと思った。

Yuki TerashimaYuki Terashima

Length of Tuple

自分の解答
type Length<T> = T['length']

さきほどの First of Array で解答を知ってしまった・・・😂

ただ、これだけだと// @ts-expect-errorのテストケースが通らないので、以下のように修正した。

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

投稿されていた他の解答もほぼ以下のような感じだった。

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

Exclude

自分の解答

これ、全然わからなかった・・・。何となくextendsを使うのではないか、ということは分かったが、それ以上どのように書けばよいか検討もつかなかった。

答えは

type MyExclude<U, T> = U extends T ? never : U;

とのことで、自分は Conditional Types における Union types の分配則を理解していないことがわかった。

参考:TypeScript 2.8 の Conditional Types について - Qiita

上記記事の例がわかりやすいが、(T1 | T2) extends U ? X : Y(T1 extends U ? X : Y) | (T2 extends U ? X : Y)と評価される。neverだと分かりにくいが、試しにnever1に変えて

type MyExclude<T, U> = T extends U ? 1 : T

としてみると、以下のように分配則が適用されていることがわかる。

type Test = MyExclude<'a' | 'b' | 'c', 'a'> // 'b' | 'c' | 1
Yuki TerashimaYuki Terashima

Awaited

自分の解答

ここで使うのがinferか!というわけで以下を試す。

type MyAwaited<T> = T extends Promise<infer U> ? U : never;

一部動いたが、Promiseがネストしているケースとエラーのケースが通らない。まずはエラーのケースが通るようにする。

type MyAwaited<T extends Promise<any>> = T extends Promise<infer U> ? U : never;

その後、最後のテストケースが通るように書き換えたが、これだとPromise<Promise<Promise<string>>>とかは通らないよねぇ・・・。

type MyAwaited<T extends Promise<any>> = T extends Promise<infer U>
  ? U extends Promise<infer K> ? K : U
  : never;

というわけで、少し書き換えて以下のようにするが、MyAwaited<U>の箇所でエラーになってしまう(UPromise<any>を満たさない)。

type MyAwaited<T extends Promise<any>> = T extends Promise<infer U> ? MyAwaited<U> : T;

というわけで、ここで解答例を見るとUのチェックも行っていた。そりゃそうか、という感じだが、惜しかったな〜。

type MyAwaited<T extends Promise<unknown>> = 
  T extends Promise<infer U> 
  ? (U extends Promise<unknown> ? MyAwaited<U> : U) 
  : never;

189 - Awaited · Issue #5608 · type-challenges/type-challenges

Yuki TerashimaYuki Terashima

If

条件分岐っぽいやつ。

自分の解答

なんかすぐ解けた。

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

他の人の解答も確認したがだいたいこんな感じだった。268 - If · Issue #1313 · type-challenges/type-challenges の例とかは割と丁寧かもしれない。

type If<C extends boolean, T, F> = C extends true ? T : C extends false ? F : never
Yuki TerashimaYuki Terashima

Concat

自分の解答

これもすぐ解けた。

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

他の解答もこんな感じだった。

Yuki TerashimaYuki Terashima

Includes

自分の解答

初見では

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

かなと思ったが、通らないケースが複数ある。

色々試行錯誤したけど結局わからなかったので解答を確認することに。ここで、初めて日本語の解答例(解答者)がないことに気がつく。他の解答を見る限りでも、テストケースが通らないものも多かったので結構難しい問題なのかもしれない。

以下が解答例。スプレッド構文で配列の最初の要素を取得しUと比較、それをループしています。

type Includes<T extends readonly any[], U> = T extends [infer F, ...infer Rest]
	? Equal<F, U> extends true
		? true
		: Includes<Rest, U>
	: false;

898 - Includes · Issue #10678 · type-challenges/type-challenges

以下、他に参考にした記事。みんな「これ初級か?」と言っている。

Yuki TerashimaYuki Terashima

Push

余談だが日本語の問題文がない。新しく追加された問題なのかな?

自分の解答

瞬殺だった。

type Push<T extends any[], U> = [...T, U]
Yuki TerashimaYuki Terashima

Parameters

記念すべき初級最後の問題(2022年5月現在)。

自分の解答

恥ずかしながら何もわからなかった😇

type MyParameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? P : never;

3312 - Parameters · Issue #10646 · type-challenges/type-challenges

なるほどinferね・・・。inferに慣れていないことが露呈してきたので鍛えていきたい💪
(現時点でもかなり Type Challenges を解く前よりも鍛えられている気がするが。)

Yuki TerashimaYuki Terashima

Get Return Type

自分の解答
type MyReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer U ? U : never;

流れるようにこの解答を導き出せるようになった自分を褒めたい。

このスクラップは2022/05/27にクローズされました