| 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 | */ |
| 7 | import { 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. |
| 15 | export 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. |
| 24 | export type UserType = typeof User["Type"] |
| 25 | |
| 26 | // Access the encoded type with `typeof YourSchema["Encoded"]`. |
| 27 | export 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. |
| 32 | export const decodeUser = Schema.decodeUnknownEffect(User) |
| 33 | export const encodeUser = Schema.encodeEffect(User) |
| 34 | |
| 35 | export class InvalidUserPayload extends Schema.TaggedError<InvalidUserPayload>()("InvalidUserPayload", { |
| 36 | message: Schema.String |
| 37 | }) {} |
| 38 | |
| 39 | export const parseUserPayload = Effect.fn("parseUserPayload")((input: unknown) => |
| 40 | decodeUser(input).pipe( |
| 41 | Effect.mapError((error) => new InvalidUserPayload({ message: error.message })) |
| 42 | ) |
| 43 | ) |