mosya<TC> - AllCombinations型を実装して、与えられた文字列のすべての組み合わせを返そうの解説
この記事はmosya<TC>の問題の一つであるAllCombinations型の解説になります。
問題
指定された文字列に含まれる文字をそれぞれ最大で1度だけ使った文字列のすべての組み合わせの型AllCombinations
を実装します。
例えば
type AllCombinations_ABC =
AllCombinations<"ABC">;
// should be '' | 'A' | 'B' | 'C' | 'AB' | 'AC' | 'BA' | 'BC' | 'CA' | 'CB' | 'ABC' | 'ACB' | 'BAC' | 'BCA' | 'CAB' | 'CBA'
解答例
type StringToUnion<S> =
S extends `${infer F}${infer R}`
? F | StringToUnion<R>
: S;
type AllCombinations<
S extends string,
T extends string = StringToUnion<S>,
U extends string = T
> = S extends `${infer F}${infer R}`
? U extends U
? `${U}${AllCombinations<
R,
U extends "" ? T : Exclude<T, U>
>}`
: never
: "";
StringToUnion
を作成
文字列をユニオン型に変換するまず、文字列をユニオン型に変換するStringToUnion
を作成します。
type StringToUnion<S> =
S extends `${infer F}${infer R}`
? F | StringToUnion<R>
: S;
この型は、与えられた文字列を、先頭の文字F
と残りの文字列R
に分割します。
もし分割に成功した場合は、それ以外の文字列R
に対して再帰的にこの型を適用します。
これを繰り返すことで、文字列をユニオン型に変換することができます。
AllCombinations
を作成
次に、AllCombinations
を作成します。
文字列S
を先頭の文字F
と残りの文字列R
に分割します。
S extends `${infer F}${infer R}`
次に、U extends U
という条件を使い、ユニオン型のU
の要素を一つずつ取り出し、再帰的に処理を適用します。
U extends U
? `${U}${AllCombinations<R, U extends '' ? T : Exclude<T, U>>}`
: never
例えば、Uが"A" | "B" | "C" | ""
の場合、"A"
、"B"
、"C"
、""
に対して、以下の処理が行われます。
`${U}${AllCombinations<
R,
U extends "" ? T : Exclude<T, U>
>}`;
まず、U
がA
の場合は、以下のように色が展開されます。
`${"A"}${AllCombinations<
R,
"A" extends ""
? "A" | "B" | "C" | ""
: Exclude<"A" | "B" | "C" | "", "A">
>}`;
文字列の先頭にAという文字が追加され、残りの文字列に対して再帰的に処理が行われます。
`${"A"}${AllCombinations<
R,
"B" | "C" | ""
>}`;
これが、文字列の長さが0になるまで繰り返されます。
`${"A"}${AllCombinations<
R,
"B" | "C" | ""
>}``${"A"}${`${"B"}${AllCombinations<
R,
"C" | ""
>}`}``${"A"}${`${"B"}${`${"C"}${AllCombinations<
R,
""
>}`}`}`;
最後に、文字列の長さが0になった場合は、空文字列を返します。
`${"A"}${`${"B"}${`${"C"}${""}`}`}`;
// 他のAから始まる組み合わせ
この処理が、B
やC
、""
に対しても同様に行われます。
`${"B"}${AllCombinations<
R,
"A" | "C" | ""
>}``${"B"}${`${"A"}${AllCombinations<
R,
"C" | ""
>}`}``${"B"}${`${"A"}${`${"C"}${AllCombinations<
R,
""
>}`}`}`;
// 他のBから始まる組み合わせ
`${"C"}${AllCombinations<
R,
"A" | "B" | ""
>}``${"C"}${`${"A"}${AllCombinations<
R,
"B" | ""
>}`}``${"C"}${`${"A"}${`${"B"}${AllCombinations<
R,
""
>}`}`}`;
// 他のCから始まる組み合わせ
Authored by
Godai@steelydylan
Webサービスを作るのが好きなWebエンジニア。子供が産まれたことをきっかけに独立し法人化。サービス開発が大好き。
好きな言語はTypeScript。