introspektion på anpassad TypeScript-typ


Jag definierar en anpassad typ i TypeScript

type MyType = 'left' | 'right';

Hur kan jag kontrollera om en variabel matchar denna typ? Hur kan jag iterera över de möjliga värdena för denna typ? (för att till exempel skapa ett motsvarande selekteringselement)

Svar #1

Att lägga till typinformation vid körning är ett uttalat icke-mål för TypeScript. Det betyder att de inte vill tillåta att du definierar en typ och sedan undersöker den vid körning.

Däremot fungerar det precis lika bra åt andra hållet: skapa ett objekt som existerar vid körning, och använd TypeScript för att härleda typinformation om det. Här är ett sätt att göra det i ditt fall.

Först, lägg till följande hjälpfunktion:

function stringLiteralArray<T extends string>(...args: T[]): T[] {
  return args;
}

Detta hjälper TypeScript att härleda en matris av strängliteraler istället för bara string[].

Nu kan du skapa ett runtime-objekt som heter myType och härleda MyType från det:

const myType = stringLiteralArray('left', 'right'); // ('left'|'right')[]
type MyType = (typeof myType)[number]; // 'left' | 'right'

Då har du både information om typ vid körning och kompilering. Du kan kontrollera om en variabel är av den typen med följande användardefinierade typvakt:

function isMyType(x: any): x is MyType {
  return myType.includes(x); // needs es2016 at least, or implement yourself
}

Du kan iterera myType vid körning, och du kan göra fullständighetskontroll på MyType vid kompileringstid:

function foo(x: MyType): string { // error, not exhaustive
  switch (x) {
    case 'left': return 'L';
    case 'rihgt': return 'R'; // error, 'rihgt' isn't 'left'|'right'
  }
}

Hoppas det hjälper.

Svar #2

Du kan inte göra det med en "enkel typ", men sedan Typescript 2.4 kan du använda enums med strängvärden:

enum MyType {
    LEFT='left',
    RIGHT='right'
}

for (let i in MyType) {
    console.log(MyType[i]); //will print "left" and "right"
}

Det fungerar eftersom under körning finns ett objekt som heter MyType och dess värde är {RIGHT:'right',LEFT:'left'}.

Relaterade artiklar