Closed renkei closed 4 days ago
Adding methods is not possible, unfortunately. The equivalent is to create a function. For example:
import type { User, Robot } from "./gen/example_pb.js";
export function getFullName(m: User | Robot): string {
switch (m.$typeName) {
case "example.User":
return `${m.firstName} ${m.lastName}`;
case "example.Robot":
return `${m.name}`;
}
}
You don't need the schema, and you can support multiple messages with a type union, and can narrow the type with the $typeName
property.
It's certainly a different style, but should work just as well in practice. It's not as self-documenting as a method, but on the other hand it's tree-shakeable.
Unfortunately, that's a pretty big restriction. We use the possibility to add some helper functions to the generated code in C# (classes are partial) and TypeScript for a long time. In TypeScript we used the google-protobuf npm package first, later we switched to your @bufbuild/protobuf v1 package. Now, with v2 this isn't possible anymore :-(
Of course, additional functions defined somewhere else is a workaround, but not so easy-to-use than a class member function and an additional significant breaking change in our code base. In the end, our approaches to implementing such extension methods will be much more divergent in our related programming languages with v2.
However, thanks for your answer and for your great job with this project! Any ideas, how long v1 will still be supported?
It was not an easy decision to remove classes. Attaching behavior to objects with methods is a good fit for Protobuf. Unfortunately, support for classes in major frontend frameworks is very poor. It would be fantastic to have C#-style extension methods in TypeScript.
We don't have plans to stop supporting v1.
With v1, the generated code was based on classes. I used the prototype-property to add additional convenience methods instead of writing a wrapper class. To make the methods which were added at runtime also available to the TypeScript compiler I used the declare module approach where I created an related interface.
This way, it was very easy to write extension methods that simplified the usage of the received messages without writing wrapper classes or external-like functions that need the message as argument.
Example with v1
Is this or something similar possible with v2 with the concept of plain objects and schemas?