Type Challenges 中級編15: Reverse, Flip Arguments, FlattenDepth
はじめに
GitHubのtype-challengesリポジトリは、TypeScript型システムの理解を深めるための型クイズ問題集です。高品質な型を作成することで、バグを減らし、プロジェクトの保守性を向上させることができます。今回も中級編から3つの問題に挑戦します。
1. Reverse
この課題では、配列を逆順にする型を実装します。これはJavaScriptの Array.reverse
の型版です。
例
type A = Reverse<['a', 'b']>; // ['b', 'a']
type B = Reverse<['a', 'b', 'c']>; // ['c', 'b', 'a']
私の回答
type Reverse<T extends Array<unknown>, U extends Array<unknown> = []> =
T extends [infer F, ...infer Rest] ? Reverse<Rest, [F, ...U]> : U;
解き方
-
Reverse
型は、ジェネリック型T
が配列であることを前提とし、再帰的に先頭要素F
を取り出して残りの要素Rest
を逆順にします。 - 基本的な考え方は、配列の先頭要素を新しい配列
U
の先頭に追加していくことです。
このようにして、配列を逆順にする新しい配列型を作成することができます。
再帰を使用して新しく配列を作ってしまえば問題ないですね!
2. Flip Arguments
この課題では、関数の引数の順序を逆にする型を実装します。これはLodashの _.flip
の型版です。
例
type Flipped = FlipArguments<(arg0: string, arg1: number, arg2: boolean) => void>;
// (arg0: boolean, arg1: number, arg2: string) => void
私の回答
type Reverse<T extends Array<unknown>, U extends Array<unknown> = []> =
T extends [infer F, ...infer Rest] ? Reverse<Rest, [F, ...U]> : U;
type FlipArguments<T> =
T extends (...args: infer ARGS) => infer R ? (...args: Reverse<ARGS>) => R : never;
解き方
-
FlipArguments
型は、関数型T
が引数ARGS
と戻り値R
を持つ場合に、引数の順序を逆にした新しい関数型を返します。 - まず、
Reverse
型を使って引数ARGS
の順序を逆にし、その結果を新しい関数型として返します。
このようにして、関数の引数の順序を逆にする型を作成することができます。
関数の引数を推定して1問前のReverseを使えば簡単ですね、
3. FlattenDepth
この課題では、配列を指定された深さ depth
まで再帰的にフラット化する型を実装します。深さが指定されていない場合は1回フラット化します。
例
type A = FlattenDepth<[1, 2, [3, 4], [[[5]]]], 2>; // [1, 2, 3, 4, [5]]. flattern 2 times
type B = FlattenDepth<[1, 2, [3, 4], [[[5]]]]>; // [1, 2, 3, 4, [[5]]]. Depth defaults to be 1
(答えを見ました、情けない、、)
type FlattenDepth<
T extends any[],
S extends number = 1,
U extends any[] = []
> = U['length'] extends S
? T
: T extends [infer F, ...infer R]
? F extends any[]
? [...FlattenDepth<F, S, [...U, 1]>, ...FlattenDepth<R, S, U>]
: [F, ...FlattenDepth<R, S, U>]
: T;
解き方
-
U
は再帰的にフラット化するためのカウンタとして使用しているようです -
U['length']
がS
に達するまで、配列の各要素をチェックし、ネストされた配列の場合は再帰的にフラット化しているようです、思いつかないだろこんなの、、
いや難しすぎる!!〇〇回繰り返す、とか難しい、、、
まとめ
これらの課題を通じて、TypeScriptの型システムに対する理解が深まり、複雑な型操作のスキルが向上します。特に、タプルや配列の操作、オブジェクト型のプロパティの操作に関する知識を強化できます。ぜひ、これらの課題に挑戦して、型の理解を深めてください。