typescript - Skapa en subklass av en klass med en statisk enum-egenskap och behåll typpinformationen
Uppföljning från: Definiera enum som statisk egenskap i klassen
I följande kod har vi en Box-klass med en Color-enum-egenskap definierad på den så att typen kan refereras med Box.Color.
class Box {
constructor(private color: Box.Color) {}
}
namespace Box {
export enum Color {
RED,
GREEN,
BLUE,
}
}
function createBox (color: Box.Color): Box {
return new Box(color);
}
const box = createBox(Box.Color.RED);
console.log(box); // { color: 0 }
Mitt problem är nu att när jag försöker subklassa Box så följer Color-egenskapen med (i JavaScript) men typinformationen följer inte med i TypeScript.
class SmallBox extends Box { }
function createSmallBox (color: SmallBox.Color): SmallBox {
// ^ Error
return new SmallBox(color);
}
const box = createSmallBox(SmallBox.Color.RED);
// ^ Works
console.log(box);
Detta fungerar i JavaScript eftersom SmallBox ärver den statiska Color-egenskapen från Box. Däremot fungerar det inte i TypeScript eftersom typinformationen går förlorad. Finns det något sätt att uppnå samma sak samtidigt som typinformationen bibehålls? Jag letar efter ett generiskt sätt som behåller all typinformation från Box och tillämpar den på SmallBox utan att behöva skapa ett nytt SmallBox-namnrymd och lista varje typ manuellt.
Redigera: Jag har kunnat komma på följande som kräver ett extra namnrymd för att skicka saker runt. Jag skulle dock gärna bli av med den extra undernamnrymden om möjligt.
class Box {
constructor(private color: Box.Subtypes.Color) {}
}
namespace Box {
export namespace Subtypes {
export enum Color {
RED,
GREEN,
BLUE,
}
}
}
function createBox (color: Box.Subtypes.Color): Box {
return new Box(color);
}
class SmallBox extends Box { }
namespace SmallBox {
export import Subtypes = Box.Subtypes;
}
function createSmallBox (color: SmallBox.Subtypes.Color): SmallBox {
// ^ Works
return new SmallBox(color);
}
const box = createSmallBox(SmallBox.Subtypes.Color.RED);
// ^ Works
console.log(box);
Svar #1
Istället för att använda enums kan du definiera ett objekt på din basklass med den önskade uppräkningen av värden med as const (en const-assertion), och sedan skapa en typalias för att representera en union av dessa uppräknade värden (BoxColor i exemplet nedan). Med detta tillvägagångssätt blir allt enklare: ingen namnutrymmes-sammanslagning, ingen enum-kodgenerering, osv.
TypeScript-lekplats
type Values<T> = T[keyof T];
export type BoxColor = Values<typeof Box.Color>; // 0 | 1 | 2
class Box {
static readonly Color = {
RED: 0,
GREEN: 1,
BLUE: 2,
} as const;
constructor(private color: BoxColor) {}
}
function createBox (color: BoxColor): Box {
return new Box(color);
}
const box = createBox(Box.Color.RED);
console.log(box); // { color: 0 }
export class SmallBox extends Box {}
export function createSmallBox (color: BoxColor): SmallBox {
return new SmallBox(color);
}
const smallBox = createSmallBox(SmallBox.Color.RED);
console.log(smallBox); // { color: 0 }
Om dina konsumenter behöver tillgång till den typen kan de bara importera den tillsammans med waardeexporterna:
import {type BoxColor, createSmallBox} from './the-module-above.mts';
