Skip to content

v6.1.0

Choose a tag to compare

@DZakh DZakh released this 28 Nov 09:29
· 543 commits to main since this 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, while S.object/S.tuple are more flexible and require you to describe the schema explicitly.

Full Changelog: v6.0.0...v6.1.0