-
Notifications
You must be signed in to change notification settings - Fork 349
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Compiler flag oneof=unions generates type unions for oneof fields instead of individual properties #95
Conversation
I can't see what the failure is, circleci wants me to log in. :( |
A transient failure @philikon This looks great. Will give it a try on my project |
@philikon one thing I noticed
the From Partial allows the user to omit the case. This seems to fix it. but here be dragons...
This forces the user to allows provide a |
A more conceptual issue: Proto
Generated Code
I think that the generated code should actually be
my reasoning is that these 2 cases are equivalent from a protobuf point of view
This also allows us to remove some tedious if statements |
Yes, I think that's the whole point of
Hmm, I need to think about this some more, but I think you might be right. Either you chose the |
(Btw, in your example you can do |
Definitely. I guess its just a bit of a footgun because erroneous code would compile. But this was not the goal of the PR I think, because the existing code has the same issue that you attempt to set multiple oneOf fields. I think a runtime exception in this case might be good enough? I tried to spin up a comparative example in go but the generation style prevents settings 2 cases of a one of field.
I almost came to the same conclusion but then there is no clean way to narrow the type
Thanks :), I was being intentionally pedantic to make sure typescript was doing the right thing. |
Wow, looks good, @philikon :) { choice: { '$case': 'aMessage', aMessage: undefined }} I think Regarding fromPartial(): I think @cliedeman is on the right track. The following seems to work out for me: export type PartialMessage<T> =
T extends (Date | Uint8Array | Long | boolean | string | number) ?
T
: T extends Array<infer U> ?
Array<PartialMessage<U>>
: T extends ReadonlyArray<infer U> ?
ReadonlyArray<PartialMessage<U>>
: T extends { oneofKind: string } ?
T
: T extends { oneofKind: undefined } ?
T
: T extends {} ?
{ [K in keyof T]?: PartialMessage<T[K]> }
: Partial<T>; You can read it like a if, else if, ... else statement. Don't think that this is a drop-in replacement, though. Have been working on yet another typescript plugin... Using the compiler api to generate .ts from .proto. Seems to work alright so far. |
I think I understand the
works great. I think it's fine to require that if I'll also remove the optionality of message payloads inside the |
5798b3a
to
2cf9ebe
Compare
…tead of individual properties Addresses stephenh#74
@stephenh any chance you could look at this over the next few days? |
Ping? |
@philikon yep, sorry, thanks for the patience; I spent my free cycles over the weekend hacking on something else. Will get to this this week. |
Awesome, thanks |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks really great, will merge and release. Thanks!
// | ||
// When oneof=unions, we generate a single property for the entire `oneof` | ||
// clause, spelling each option out inside a large type union. No need for | ||
// union with `undefined` here, either. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great comment, thanks!
if (options.oneof === OneofOption.UNIONS) { | ||
oneofCase = ` | ||
: T extends { $case: string } | ||
? { [K in keyof Omit<T, '$case'>]?: DeepPartial<T[K]> } & { $case: T['$case'] }`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice
|
||
// Ideally we'd put the comments for each oneof field next to the anonymous | ||
// type we've created in the type union above, but ts-poet currently lacks | ||
// that ability. For now just concatenate all comments into one big one. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks again for the in-source comment.
@@ -604,6 +679,9 @@ function generateDecode( | |||
.addStatement(`message.%L.push(%L)`, fieldName, readSnippet) | |||
.endControlFlow(); | |||
} | |||
} else if (isWithinOneOf(field) && options.oneof === OneofOption.UNIONS) { | |||
let oneofName = maybeSnakeToCamel(messageDesc.oneofDecl[field.oneofIndex].name, options); | |||
func = func.addStatement(`message.%L = {$case: '%L', %L: %L}`, oneofName, fieldName, fieldName, readSnippet); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huh, that wasn't too bad. Nice.
Woot! Thank you! |
Addresses #74