Är det möjligt att skapa en TypeScript-typ från en array?
Jag använder ofta kod som
export type Stuff = 'something' | 'else'
export const AVAILABLE_STUFF: Stuff[] = ['something', 'else']
På det här sättet kan jag både använda typen Stuff och iterera över alla tillgängliga stuffs om det behövs.
Detta fungerar, men det känns som att upprepa informationen två gånger. Och du måste vara försiktig eftersom en uppdatering av antingen Stuff eller AVAILABLE_STUFF också kräver en uppdatering av dess motsvarighet.
Finns det ett bättre sätt att definiera typen från arrayen, eller till och med på något sätt använda arrayen för att typa viss data?
Svar #1
Med TypeScript v3.4 const-utsagor:
export const AVAILABLE_STUFF = <const> ['something', 'else'];
export type Stuff = typeof AVAILABLE_STUFF[number];
Svar #2
Ett inbyggt alternativ skulle vara att använda en enum istället för typen och arraymetoden.
export enum Stuff {
something = 'something',
else = 'else',
}
export const AVAILABLE_STUFF: Stuff[] = Object.values(Stuff);
Ett annat alternativ är att extrahera typen från typen av AVAILABLE_STUFF. För att göra detta måste vi tvinga kompilatorn att härleda en tuple av strängliteral för AVAILABLE_STUFF. Detta kan göras i 3.4 med as const eller före 3.4 med hjälp av en extra funktion. När AVAILABLE_STUFF är en tuple-typ kan vi helt enkelt använda en typfråga för att få typen av elementen:
export const AVAILABLE_STUFF = (<T extends string[]>(...o: T)=> o)('something', 'else'); // typed as ["something", "else"]
// export const AVAILABLE_STUFF = ['something', 'else'] as const; // typed as ["something", "else"] in 3.4
export type Stuff = typeof AVAILABLE_STUFF[number] //"something" | "else"
Några förklaringar av ovanstående kod. typeof AVAILABLE_STUFF ger oss typen av konstanten (["something", "else"]); för att få [number] kallas det för en typförfrågan och kommer att ge oss typen av ett element i tuple:n.
(<T extends string[]>(...o: T)=> o) är bara ett IIFE som vi använder för att tvinga kompilatorn att härleda en tuple-typ med strängliteraler. Den måste vara generisk eftersom kompilatorn endast kommer att härleda literaltyper och tuples i vissa fall (en typparameter med en begränsning av string är ett av dem). as const-versionen är den jag skulle rekommendera att använda när den blir tillgänglig eftersom den är mer läsbar.
