In tackling this problem, there are two main approaches to consider: creating a function for inference and validation or forming a union of all permissible states.
enum Color {
red,
green,
yellow,
blue,
black,
white,
}
type RequiredElements = Color.black | Color.white
const withRequired = <
Item extends Color,
List extends Item[]
>(list: RequiredElements[] extends [...List] ? List : never) => list
const ok = withRequired([Color.red, Color.yellow, Color.black, Color.white]) // ok
const error = withRequired([Color.red, Color.yellow, Color.black]) // error
check out the code here
Alternatively,
enum Color {
red,
green,
yellow,
blue,
black,
white,
}
// Link to relevant issue for context: https://github.com/microsoft/TypeScript/issues/13298#issuecomment-692864087
type TupleUnion<U extends string | number, R extends any[] = []> = {
[S in U]: Exclude<U, S> extends never
? S extends Color.black | Color.white
? [...R, S] : [...R, S?] : TupleUnion<Exclude<U, S>,
S extends Color.black | Color.white ? [...R, S]
: [...R, S?]
>;
}[U];
type Ok = TupleUnion<Color>
export const Correct: Ok = [Color.red, Color.yellow, Color.black, Color.white]; // ok
export const COrrect1: Ok = [Color.red, Color.white, Color.yellow, Color.black]; // ok
export const Wrong1: Ok = [Color.red, Color.yellow]; // error
export const Wrong2: Ok = [Color.red, Color.green, Color.black]; // error
Access the Playground
By considering all possible states of this array, I have created an algorithm that accounts for 6! = 6 * 5 * 4 * 3 * 2 * 1 combinations.
The TupleUnion
function generates a blend of all permissible states while rendering non-black and white colors optional.