tjjfvi/subshape

Codecs Into X Y Z

Closed this issue · 2 comments

Let's say I want to represent the following type.

interface Source {
  a: number;
  b: boolean;
  c: string;
}

I can easily define its codec.

const $source = $.object(
  ["a", $.u8],
  ["b", $.bool],
  ["c", $.str],
);

And I can even extract the static type from that codec.

type SourceFromCodec = $.Native<typeof $source>;

However, what if I want to derive another representation, such as a JSON schema or a codec of another "runtype" lib?

Our Use Case

We may want to use this library as the basis for declaring types in a TS-based smart contract authoring DX. This experience would depend on our ability to serialize any codec into a corresponding Solidity type AST.

const node = toSolidityTypeAst($source);

How would we implement toSolidityTypeAst? We don't associate codecs with concrete names. We don't have the ability to perform distinct instanceof checks per codec.

What is the best approach to extending the runtype functionality of a Codec?

I think the best approach would be to add a field _metadata?: unknown to the Codec type. Then, codecs like array can add _metadata: [array, $el] (there, array refers to the function, which is a convenient unique marker). This allows for metadata, while keeping it lightweight (no external type definitions or unique symbols) and extensible.

This does make consumption of the metadata somewhat unergonomic (as it is ad-hoc and untyped), but I think this is a reasonable tradeoff.

I agree with this approach. How might the resulting visitor DX look?

const visitCodec = $.visitor(
  [$.u8, (codec) => {
    // ...
  }],
  [$.sizedArray, (codec) => {
    return visitCodec(codec._metadata[1]);
  }]
)

In this example of what a visitor could look like, visitCodec doesn't lend itself to type-level assurances that a given type's visitor is defined but once. A bit clunky. Ideally, child types could be accessed without codec._metadata[1]... but it's an internal detail.

Adding to the backlog