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。