Finns det ett sätt att dynamiskt generera enums i TypeScript baserat på objektets nycklar?
Jag definierar ett objekt och jag vill dynamiskt generera en enum baserat på dess nycklar, så att jag får IDE-förslag och inte använder fel nycklar.
const appRoutes = {
Login,
Auth,
NotFound
}
enum AppRoutes = {[Key in keyof appRoutes]: [keyof appRoutes]}
Svar #1
Du kan inte bygga ett faktiskt enum från objektets nycklar.
Du kan få en förening av alla nycklar med bara keyof typeof appRoutes och det kommer att ha den typ-säkra effekten du vill ha:
type AppRoutes = keyof typeof appRoutes
let ok: AppRoutes = "Auth";
let err: AppRoutes = "Authh";
En enum är inte bara en typ, det är också ett runtime-objekt som innehåller nycklarna och värdena för en enum. Typescript erbjuder inte ett sätt att automatiskt skapa ett sådant objekt från en strängunion. Vi kan dock skapa en typ som säkerställer att nycklarna i ett objekt och medlemmarna i unionen hålls i synk och vi får ett kompilatorfel om de inte är i synk:
type AppRoutes = keyof typeof appRoutes
const AppRoutes: { [P in AppRoutes]: P } = {
Auth : "Auth",
Login: "Login",
NotFound: "NotFound" // error if we forgot one
// NotFound2: "NotFound2" // err
}
let ok: AppRoutes = AppRoutes.Auth;
Svar #2
Jag använder denna lösning för att konvertera nycklarna till ett const key -> key-objekt:
const { Login, Auth, NotFound } = {} as any
const appRoutes = {
Login,
Auth,
NotFound
}
const AppRoutes = (() => ({
...Object.keys(appRoutes)
.filter(k => isNaN(Number(k)))
.reduce((acc, cur) => ({
...acc,
[cur]: cur,
}), {}),
} as {
[k in keyof typeof appRoutes]: k
}))()
console.info(AppRoutes)
// AppRoutes: {
// Login: "Login";
// Auth: "Auth";
// NotFound: "NotFound";
// }
