javascript - Se till att arrayen har alla typer från en union


Säg att jag har en union som ser ut så här

type Colors = 'red' | 'blue' | 'pink'

Är det möjligt att typkontrollera en array mot denna union och se till att arrayen innehåller alla typerna?

D.v.s.:

const colors: UnionToTuple<Colors> = ['red', 'blue']  // type error, missing 'pink'
const colors: UnionToTuple<Colors> = ['red', 'blue', 'pink']  // no error

Svar #1

Genom att ta idéer från detta svar kan du skapa en funktion som typkontrollerar genom att använda en typparameter för den passerade arrayen, T. Typa den som T extends Colors[] för att säkerställa att varje objekt i arrayen finns i Colors, och typa den också som [Colors] extends [T[number]] ? unknown : 'Invalid' för att säkerställa att varje objekt av typen Colors finns i den passerade arrayen:

type Colors = 'red' | 'blue' | 'pink';
const arrayOfAllColors = <T extends Colors[]>(
  array: T & ([Colors] extends [T[number]] ? unknown : 'Invalid')
) => array;

const missingColors = arrayOfAllColors(['red', 'blue']); // error
const goodColors = arrayOfAllColors(['red', 'blue', 'pink']); // compiles
const extraColors = arrayOfAllColors(['red', 'blue', 'pink', 'bad']); // error

Mer generellt, omslut det i en annan funktion så att du kan skicka och använda en typparameter av unionstypen:

type Colors = 'red' | 'blue' | 'pink';
const arrayOfAll = <T>() => <U extends T[]>(
  array: U & ([T] extends [U[number]] ? unknown : 'Invalid')
) => array;
const arrayOfAllColors = arrayOfAll<Colors>();

const missingColors = arrayOfAllColors(['red', 'blue']); // error
const goodColors = arrayOfAllColors(['red', 'blue', 'pink']); // compiles
const extraColors = arrayOfAllColors(['red', 'blue', 'pink', 'bad']); // error

Svar #2

Lösningen från @CertainPerformance avvisar inte tomma arrayer. Här är en lösning:

const arrayOfAll = <T>() => <U extends T[]>(
  array: U & ([T] extends [U[number]] ? unknown : 'Invalid') & { 0:T }
) => array;

Relaterade artiklar