Hyperlinkv0.8.0-beta.28

Schema

Schema.extendTofunctioneffect/Schema.ts:3614
<S extends Struct<Struct.Fields>, const Fields extends Struct.Fields>(
  fields: Fields,
  derive: {
    readonly [K in keyof Fields]: (
      s: S["Type"]
    ) => Option_.Option<Fields[K]["Type"]>
  }
): (
  self: S
) => decodeTo<
  Struct<
    Simplify<
      { [K in keyof S["fields"]]: toType<S["fields"][K]> } & Fields
    >
  >,
  S
>

Adds derived fields to a struct schema during decoding.

Details

Each new field is derived from the decoded struct value via a function that returns Option. On encoding the derived fields are stripped. This allows computed or enriched fields to live in the decoded type without appearing in the encoded form.

Example (Adding a computed fullName field)

import { Option, Schema } from "effect"

const Person = Schema.Struct({ first: Schema.String, last: Schema.String })
const Extended = Person.pipe(
  Schema.extendTo(
    { fullName: Schema.String },
    { fullName: (p) => Option.some(`${p.first} ${p.last}`) }
  )
)

const alice = Schema.decodeUnknownSync(Extended)({ first: "Alice", last: "Smith" })
console.log(alice.fullName)
// Alice Smith
transforming
Source effect/Schema.ts:361436 lines
export function extendTo<S extends Struct<Struct.Fields>, const Fields extends Struct.Fields>(
  /** The new fields to add */
  fields: Fields,
  /** A function per field to derive its value from the original input */
  derive: { readonly [K in keyof Fields]: (s: S["Type"]) => Option_.Option<Fields[K]["Type"]> }
) {
  return (
    self: S
  ): decodeTo<Struct<Simplify<{ [K in keyof S["fields"]]: toType<S["fields"][K]> } & Fields>>, S> => {
    const f = Record_.map(self.fields, toType)
    const to = Struct({ ...f, ...fields })
    return self.pipe(decodeTo(
      to,
      SchemaTransformation.transform({
        decode: (input) => {
          const out: any = { ...input }
          for (const k in fields) {
            const f = derive[k]
            const o = f(input)
            if (Option_.isSome(o)) {
              out[k] = o.value
            }
          }
          return out
        },
        encode: (input) => {
          const out = { ...input }
          for (const k in fields) {
            delete out[k]
          }
          return out
        }
      })
    )) as any
  }
}