Search code examples
typescriptdecoder

Intersection of two [or more] decoders


Let's say two decoders are already defined:

import * as D from "decoders"
const named = D.object({
  firstName: D.string,
  lastName: D.string
})

const aged = D.object({
  age: D.number
})

How do I get an intersection of these existing decoders, such it validates for an object containing properties from both?

const person: D.Decoder<{
  firstName: string,
  lastName: string,
  age: number
}> = D.???(named, aged)

Solution

  • It doesn't look like the library has a function for that.
    Here is how it could be done

    import { Ok } from "lemons/Result";
    function combine<A, B>(decoder1: D.Decoder<A>, decoder2: D.Decoder<B>): D.Decoder<A & B> {
      return (blob: unknown) =>
        decoder1(blob).andThen((v1) => decoder2(blob).andThen((v2) => Ok({ ...v1, ...v2 })));
    }
    
    const person = combine(aged, named);
    

    Or if the decoders are inexact instead of object:
    (This will fail if they are not inexact and the type checker won't catch it)

    function combine<A, B>(d1: D.Decoder<A>, d2: D.Decoder<B>) {
      return D.compose(d1, d2) as unknown as D.Decoder<A & B>;
    }