Other schema libraries allow only to decode data (zod
comes to mind):
import { z } from "zod";
const Author = z.object({
name: z.string(),
age: z.number(),
});
const author = Author.parse(someData);
In this example parse
allows to verify that someData
conforms to the Author
schema. Since there is no input/output transformation in Author
, encoding is not that useful.
See however what happens here:
const Author = z.object({
name: z.string(),
age: z.string().transform((ageString) => Number(ageString)),
});
By using transform
the type of age
is different from input (string
) to output (number
). When we parse
on this new Author
schema we get { name: string; age: number; }
.
What if we need to encode back to the original shape { name: string; age: string; }
?
No easy solution at the moment with zod
.
Schema encoding
The unique feature of @effect/schema
that makes it stand apart from other schema libraries is encoding.
In fact, @effect/schema
includes out-of-the-box APIs to convert between types. The same Author
schema looks like this:
import { Schema } from "@effect/schema";
const Author = Schema.Struct({
name: Schema.String,
age: Schema.NumberFromString,
});
With Schema.decodeSync
we achieve the same as parse
in zod
:
/// 👇 { readonly name: string; readonly age: number; }
const authorDecoded = Schema.decodeSync(Author)({ age: "26", name: "Sandro" });
What if we now want to do the inverse? Schema.encodeSync
is the answer:
const authorDecoded = Schema.decodeSync(Author)({ age: "26", name: "Sandro" });
/// 👇 { readonly name: string; readonly age: string; }
const authorEncoded = Schema.encodeSync(Author)(authorDecoded);
When to encode data
When is encoding needed?
When we decode a schema the goal is usually to verify and parse some primitive value (for example a JSON response) to an internal representation that works for our app.
Think of decoding as some data coming from outside to the inside.
Often times the decoded schema contains non-serializable values (Map
, Set
, class
).
When we then want to send the data back we need the inverse process: encoding. We convert non-serializable values to a format that can be sent to an external service.
Think of encoding as some data going from inside to the outside.
@effect/schema
offers an API specifically designed for all the steps since it includes both decoding and encoding in one single schema definition.