Letting you know that a few days ago rescript-struct
was renamed to rescript-schema
. It wasn’t an easy decision since rescript-struct
has already become a well-known name, but I think it was right to make the change. Actually, I felt so relieved after this, I didn’t imagine that the name bothered me so much.
The primary motivation for the rename was that I chose the original struct
naming by coincidence:
- I couldn’t find good free package names on npm
- The first versions of the package were inspired by
superstruct
, so I thought that thestruct
name was fine.
But the problem with a struct
is that in many languages, it has its own meaning, and for many people, I had to explain that struct
is the same thing as schema
, but just called differently. So, to avoid the confusion, rescript-struct
was renamed to rescript-schema
You can install it from npm:
npm install rescript-schema
Also, after the rename, I’ve just done a feature release
New S.schema
helper
(schemaCtx => 'value) => S.t<'value>
It’s a helper built on S.literal
, S.object
, and S.tuple
to create schemas for runtime representation of ReScript types conveniently.
@unboxed
type answer =
| Text(string)
| MultiSelect(array<string>)
| Other({value: string, @as("description") maybeDescription: option<string>})
let textSchema = S.schema(s => Text(s.matches(S.string)))
// It'll create the following schema:
// S.string->S.variant(string => Text(string))
let multySelectSchema = S.schema(s => MultiSelect(s.matches(S.array(S.string))))
// The same as:
// S.array(S.string)->S.variant(array => MultiSelect(array))
let otherSchema = S.schema(s => Other({
value: s.matches(S.string),
maybeDescription: s.matches(S.option(S.string)),
}))
// Creates the schema under the hood:
// S.object(s => Other({
// value: s.field("value", S.string),
// maybeDescription: s.field("description", S.option(S.string)),
// }))
// Notice how the field name /|\ is taken from the type's @as attribute
let tupleExampleSchema = S.schema(s => (#id, s.matches(S.string)))
// The same as:
// S.tuple(s => (s.item(0, S.literal(#id)), s.item(1, S.string)))
Also, it works fantastic with discriminated unions:
@tag("kind")
type shape =
| @as("circle") Circle({radius: float})
| @as("square") Square({x: float})
| @as("triangle") Triangle({x: float, y: float})
// With S.schema
let circleSchema = S.schema(s => Circle({
radius: s.matches(S.float),
}))
// With S.object
let circleSchema = S.object(s => {
s.tag("kind", "circle")
Circle({
radius: s.field("radius", S.float),
})
})
Note that
S.schema
relies on the runtime representation of your type, whileS.object
/S.tuple
are more flexible and require you to describe the schema explicitly.