Improve support for `oneof` fields
See original GitHub issueAfter using protobuf-es-generated code a bit more, I’m going to expand on my comment in another issue and make it an issue of its own.
Currently, accessing oneof
fields in code generated by protobuf-es is a bit more cumbersome than in other protobuf code generators. In my protobuf definition I’ve got a oneof that might be a post
, comment
or profile
. Both protoc-gen-ts in TypeScript and rust-protobuf provide ways to quickly access or set a .post
. So in TypeScript I can do something like:
let post = item.post
if (post) {
// ...
}
or
item.post = new Post(...)
But in code generated by protobuf-es, I have to do:
let post: Post|undefined = undefined
let it = item.itemType
if (it.case == "post") { post = it.value }
if (post) {
// ...
}
which ends up in my code so often that I made a helper function for myself.
// Helper function for getting inner Item types.
export function getInner(item: pb.Item, field: "post"): pb.Post | undefined;
export function getInner(item: pb.Item, field: "profile"): pb.Profile | undefined;
export function getInner(item: pb.Item, field: "comment"): pb.Comment | undefined;
export function getInner(item: pb.Item, field: "post"|"profile"|"comment"): pb.Post | pb.Profile | pb.Comment | undefined {
let it = item.itemType
if (it.case == field) {
return it.value
}
}
And I just discovered that when I set a field, I have to do:
// Nope: item.comment = comment
item.itemType = {case: "comment", value: comment}
It would be nice if generated code would just expose oneof
fields as top-level fields (or properties) like other protobuf generators.
All that said, really enjoying protobuf-es so far. Native ESMsupport works so much more nicely than trying to get Google’s protobuf implementation to compile to all my targets. 😄
Issue Analytics
- State:
- Created 9 months ago
- Comments:8 (2 by maintainers)
Top GitHub Comments
I believe that setup would make it more painful to generically handle the oneof as I don’t thinks there’s a way to use a
switch
at all.Object.keys(item.oneof)[0]
is juststring
and even if cast tokeyof typeof item.oneof
that still won’t narrow the value. This means the only way to generically handle a oneof would be via if-statements checking that the property value wasn’tundefined
.So let’s imagine that instead of just
Post
orProfile
we had a dozen different messages that were part of theoneof
. And let’s also imagine each message had a common field, a stringid
, that we wished to return from a function.Another thing to consider is how the number of fields inside the oneof would drastically increase the size of the type in the generated code:
@timostamm Thanks again for the script. worked perfectly but two things i had to do
chmod +x protoc-gen-oneofhelper.ts
Not the exact migration 1:1 but works fine as I can just do an
import as
to rename it to the desired name 👍🏾