While I was pondering API design concepts, a thought crossed my mind. Is it feasible to define a type in this manner?
type SpecialArray<Unique, Bland> = [...Bland[], Unique, ...Bland[]];
However, the error message "A rest element cannot follow another rest element" quickly became apparent.
The closest approximation I could achieve is:
type SpecialArray<Unique, Bland> = [...Bland[], Unique] | [Unique, ...Bland[]];
This setup confines the "unique" element to either the beginning or end of the array. It's worth noting that at least one element (the unique one) must be present in the array.
I have come across Typescript: only allow one occurrence of a value in an array, but none of the proposed solutions catered for arrays of varying lengths. My search for alternative solutions yielded no results. One potential approach would involve using a helper function to enforce/infer the type, as shown below:
type Count<A extends readonly any[], T, Counter extends any[] = []> = A extends [infer H, ...infer R] ? [H] extends [T] ? Count<R, T, [...Counter, H]> : Count<R, T, Counter> : Counter;
type IsSpecial<A extends readonly any[], Unique, Bland> =
Count<A, Unique>["length"] extends 1
? A[number] extends Unique | Bland
? A
: never
: never;
function helper<A extends readonly any[]>(array: IsSpecial<[...A], string, number>) { return array; }
What I'm aiming for is a type that allows me to use syntax like this instead:
const checked: SpecialArray<string, number> = [...];
Is such a concept viable? I am open to accepting a solution related to
SpecialArray<Unique, Bland>
, an alternate approach different from mine, or simply a straightforward "no" accompanied by an explanation of its impossibility.
For a partial credit score (80% 😉), consider implementing
SpecialArray<Unique, Bland, MaxLength>
, which functions up to a specified length (akin to a permutation generator).
Please bear in mind that I require some form of compile-time verification.