1/**
2 * @title Schema basics
3 *
4 * Define `Schema.Class`s, decode unknown input into typed values, and
5 * encode typed values back into their external representation.
6 */
7import { Effect, Schema } from "effect"
8
9// Schema.Class defines both a runtime validator and a TypeScript class.
10// This is useful for domain models that should only be constructed from valid
11// data.
12//
13// The static `Type` and `Encoded` members are available when you need
14// the decoded or encoded TypeScript representation.
15export class User extends Schema.Class<User>("path/to/module/User")({
16 id: Schema.Int,
17 name: Schema.NonEmptyString,
18 email: Schema.String,
19 role: Schema.Literals(["admin", "member"])
20}) {}
21
22// `UserType` will be the type `User`, as schema classes use the class type as
23// the validated type.
24export type UserType = typeof User["Type"]
25
26// Access the encoded type with `typeof YourSchema["Encoded"]`.
27export type UserEncoded = typeof User["Encoded"]
28
29// Reuse parsers at the edges of your application instead of rebuilding them for
30// every request. Use the Effect-returning APIs when you are already inside
31// Effect code so validation errors remain typed in the error channel.
32export const decodeUser = Schema.decodeUnknownEffect(User)
33export const encodeUser = Schema.encodeEffect(User)
34
35export class InvalidUserPayload extends Schema.TaggedError<InvalidUserPayload>()("InvalidUserPayload", {
36 message: Schema.String
37}) {}
38
39export const parseUserPayload = Effect.fn("parseUserPayload")((input: unknown) =>
40 decodeUser(input).pipe(
41 Effect.mapError((error) => new InvalidUserPayload({ message: error.message }))
42 )
43)