Is it possible to build a repeat with template literal types? For example:
type Hex = 'a' | 'b' | 'c'| ...; type Id = `${Hex}${Hex}...` // Here I want to say Id is N hex long. In principle, this is possible with recursive conditional types in TS 4.1:
type Decrement = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] type RepeatString<S extends string, N extends number> = N extends 1 ? S : `${S}${RepeatString<S, Decrement[N]>}` type T11 = Decrement[5] // 4 type T12 = RepeatString<"foo", 3> // "foofoofoo" type T13 = RepeatString<Hex, 3> // "aaa" | "aab" | ... | "ccb" | "ccc" Beware of the following limitation:
Beware that the cross product distribution of union types can quickly escalate into very large and costly types. Also note that union types are limited to less than 100,000 constituents [.] (my emphasis)
For example, with Hex2 being 'a' | 'b' | ... | 'i' | 'j' (10 union parts), type T14 = RepeatString<Hex2, 5> will trigger following error (10*10*10*10*10 permutations):
Expression produces a union type that is too complex to represent.(2590)
In this case, it is needed to reduce the number of union parts, like finding bigger chunks of strings instead of atomic chars.
type RepeatStringAlt<S extends string, N extends number> = RepeatStringAltRec<S, TupleOf<unknown, N>> type RepeatStringAltRec<S extends string, T extends unknown[]> = T["length"] extends 1 ? S : `${S}${RepeatStringAltRec<S, DropFirst<T>>}` type TupleOf<T, N extends number> = N extends N ? number extends N ? T[] : _TupleOf<T, N, []> : never; type _TupleOf<T, N extends number, R extends unknown[]> = R['length'] extends N ? R : _TupleOf<T, N, [T, ...R]>; type DropFirst<T extends readonly unknown[]> = T extends readonly [any?, ...infer U] ? U : [...T]; type T23 = RepeatStringAlt<"foo", 3> // "foofoofoo" This gets rid of counting the number range manually with Decrement.
${Hex}${Hex}...produces all pair of union type