I'm working with TypeScript and I have the following types:
type Social = "facebook" | "twitter" | "instagram";
type Fields = "firstName" | "surname";
type PossibleFields = [Social, ...Fields[]];
I want to create a type PossibleFields where the array contains exactly one field from Social and any number of fields from Fields[], but the order doesn't matter.
I know that this solution may not be the most optimal, but I am curious if this type definition is even possible. I want to ensure that:
Is there a way to express this in TypeScript?
Thank you for your help!
I attempted to define the type PossibleFields as follows:
type Social = "facebook" | "twitter" | "instagram";
type Fields = "firstName" | "surname";
type PossibleFields = [Social, ...Fields[]];
Given the small number of the unions' members you could calc all possible tuples (around 30). As a bonus you will have IntelliSense for your typing:
type Social = "facebook" | "twitter" | "instagram";
type Fields = "firstName" | "surname";
type Insert<
T extends unknown[],
U
> =
T extends [infer F,...infer L]
? [F,U,...L] | [F,...Insert<L,U> ]
: [U]
type PermutationsOfTuple<
T extends unknown[],
R extends unknown[] = T
> =
T extends [infer F,...infer L]?
PermutationsOfTuple<L,Insert<R,F> | [F,...R] >
:R
type OptionalTuples<T, K=T> =
[T] extends [never]
? []
: K extends K
? [] | [K] | [K, ...OptionalTuples<Exclude<T, K>>]
: never
type PossibleFields = {[K in Social]: [K] | PermutationsOfTuple<[K], OptionalTuples<Fields>>}[Social];
const fields: PossibleFields = ['facebook', 'firstName', 'surname']; // ok
const fields2: PossibleFields = ['surname', 'facebook']; // ok
const fields3: PossibleFields = ['surname']; // Social missing
const fields4: PossibleFields = ['facebook', 'instagram']; // Social doubled