unsplash / sum-types

Safe, ergonomic, non-generic sum types in TypeScript.
https://unsplash.github.io/sum-types/
MIT License
42 stars 2 forks source link

Serialize nested values #43

Closed OliverJAsh closed 2 years ago

OliverJAsh commented 2 years ago

Consider this sum type which has another sum type nested inside of it. When we call Sum.serialize, only the outer sum type is serialized. The nested sum type is not serialized.

import * as Sum from "@unsplash/sum-types";
import { pipe } from "fp-ts/lib/function";

type Inner = Sum.Member<"Foo"> | Sum.Member<"Bar">;
type Outer = Sum.Member<"A"> | Sum.Member<"B", Inner>;

const Outer = Sum.create<Outer>();

declare const outer: Outer;

const serialized = pipe(outer, Sum.serialize);
//    ^? const serialized: readonly ["A", null] | readonly ["B", Inner]

Likewise, consider this sum type which has a Date inside of it. When we call Sum.serialize, only the outer sum type is serialized. The Date inside is not serialized.

import * as Sum from "@unsplash/sum-types";
import { pipe } from "fp-ts/lib/function";

type MySum = Sum.Member<"A"> | Sum.Member<"B", Date>;

const MySum = Sum.create<MySum>();

declare const mySum: MySum;

const serialized = pipe(mySum, Sum.serialize);
//    ^? const serialized: readonly ["A", null] | readonly ["B", Date]

How should we handle situations like this?

Perhaps we need an API like this:

const serialized = pipe(
  mySum,
  Sum.serialize({
    B: serializeDate
  })
);
const deserialized = pipe(
  serialized,
  Sum.deserialize<MySum>({
    B: deserializeDate
  })
);
samhh commented 2 years ago

Serialisation from within the core library is very thin and really only serves to remove the Symbol wrappers from our keys. The expectation is that, given that serialisation is such a large area of concern, this is then handed off to something like io-ts, as in our bindings.