protobuf-es icon indicating copy to clipboard operation
protobuf-es copied to clipboard

Support for custom field mapping / converter / wrapper

Open noguespi opened this issue 8 months ago • 1 comments

It would be great if we could convert some protobuf field type to custom typescript type using a user provided mapper.

It is a very useful feature allowing to avoid having to recreate intermediate classes and doing mapping between protobuf generated class and "slightly better typed" classes.

Now the generated classes would have a very good typing natively.

A concrete example is a timestamp: some people want to use native Date, others will want to map it to a more specialized type of a library.

Same could apply to UUID or other Id classes, it could use a bytearray in protobuf (optimum space usage) but be represented a custom UUID class in the generated classes.

Here is a library implementing this pattern with kotlin.

Imagine the following protobuf:

message MyMessage {
  string id = 1 [(wrapper) = "UUID"];
  string timestamp = 2 [(wrapper) = "LocalDateTime"];
}

It would generate the following class:

export type MyMessage = Message<"MyMessage"> & {
  id: UUID;
  timestamp: LocalDateTime;
};

We would just need to find a way to pass the classes implementing the Converter:

interface Converter<FROM, TO> {
  serialize(obj: FROM): TO
  deserialize(obj: TO): FROM
}

class LocalDateTimeConverter implements Converter<string, LocalDateTime> {
  deserialize(obj: LocalDateTime): string {
    return obj.toString();
  }
  serialize(obj: string): LocalDateTime {
    return LocalDateTime.parse(obj);
  }
}

And toBinary/toJson/... could just use the converter before sending/receiving from the wire.

noguespi avatar Jun 20 '25 09:06 noguespi

Hey @noguespi, gogo/protobuf has a similar feature.

Issues that could be supported with this feature:

  • https://github.com/bufbuild/protobuf-es/issues/1031
  • https://github.com/bufbuild/protobuf-es/issues/1015
  • https://github.com/bufbuild/protobuf-es/issues/703
  • https://github.com/bufbuild/protobuf-es/issues/227
  • https://github.com/bufbuild/protobuf-es/issues/226
  • https://github.com/bufbuild/protobuf-es/issues/1074

Note that the Protobuf option on the fields would have to specify how to import the type, which means it has to provide a name (e.g. "LocalDateTime") and a source (e.g. "somepackage").

The approach is not without downsides. For example, users must provide matching converters, and generating speed-optimized serialization code becomes impossible. Before designing and implementing this feature, we will need to explore alternatives.

timostamm avatar Jun 23 '25 18:06 timostamm

Hi @timostamm, did you have a chance to look into this?

We use binary ULIDs in Protobuf with a special type, which at the moment means we have to either:

  1. Manually convert them back and forth every time we use them
  2. Build an extra abstraction layer on top of Protobuf-ES which would convert the ID fields into ULIDs

Neither solution is as elegant as adding custom field mapping in the Protobuf-ES codegen & serialization process. The downsides you mentioned seem much more acceptable compared to the above alternatives, especially since they should not affect users who don't need this feature.

Tomaszal avatar Jan 13 '26 14:01 Tomaszal