Intersection of type schema and record with enums as keys
How to create schema for this object?
{
base: { version: "v1" }, // may be "v2", etc
en: { /* lang constant */ },
ge: { /* lang constant */ },
fr: { /* lang constant */ },
/* ... long list of languages ... */
}
I've found https://github.com/ianstormtaylor/superstruct/issues/1162#issuecomment-1860205487, https://github.com/ianstormtaylor/superstruct/issues/480#issuecomment-733274941:
intersection([
type({ version: enum(["v1", "v2"]) }),
record(string() /* <-- should be enums(["en", ... ]) */, LangConstant)
])
But the problem is, as stated in the comment, that I lose list of remaining keys of the object. And even if I use enums() instead of string() as key, the schema wont validate properly (because of missing base key or wrong value type below base). So there are options:
- Add all languages in a object schema:
s.object({
base: object({ version: enum(["v1", "v2"]) }),
en: LangConstant,
ge: LangConstant,
/* ...other languages */
});
- Add helpers:
const languages = ["en", "ge", /* ...other languages */];
const langsSchema = langs.reduce((acc, lang) => {
return { ...acc, [lang]: LangConstant };
}, {});
s.object({
base: object({ version: enum(["v1", "v2"]) }),
...langsSchema,
});
But the first one have a lot of repetition, and second have a separation from superstruct.
Is there a more concise way to specify such schema?
For now I'm using a condensed option similar to 2:
const langsSchema = Object.fromEntries([
"en", "ge", "fr",
/* ... */
].map(lang => ([lang, s.object({
/* ... */
})
])));
I just close it with this as the solution.
I added a comment to another issue with a slightly different approach using a custom superstruct utility function mappedObject().
Only downside is that one needs to define every single key explicitly.