Schema encoding

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.