Skip to content
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

Regression: enum strings are broken in constructor of message types in 1.8.0 #752

Closed
Azuka opened this issue Mar 19, 2024 · 3 comments
Closed

Comments

@Azuka
Copy link

Azuka commented Mar 19, 2024

I recently upgraded @bufbuild/protoc-gen-es and @bufbuild/protobuf to 1.8.0 which seemed to break some behavior when constructing messages. Given:

enum ProjectSort {
  PROJECT_SORT_UNSPECIFIED = 0;
  PROJECT_SORT_NAME = 1;
}

message ProjectServiceListRequest {
  ProjectSort sort = 1;
}

In both versions 1.7.2, and 1.8.0 the below works

const list = new ProjectServiceListRequest({sort: ProjectSort.SORT_NAME});
list.toJson();

but

const list = new ProjectServiceListRequest({sort: 'PROJECT_SORT_JOB_NUMBER'});
list.toJson(); // fails on 1.8.0

fails.

I've worked around that by forcing a conversion using proto3.getEnumType, but this was affecting client calls using connectrpc and breaking serialization.

Is this intended behavior, or was a regression introduced?

@Azuka Azuka changed the title Regression: enum strings are broken in constructor of message types from 1.72 to 1.80 Regression: enum strings are broken in constructor of message types in 1.80 Mar 19, 2024
@Azuka Azuka changed the title Regression: enum strings are broken in constructor of message types in 1.80 Regression: enum strings are broken in constructor of message types in 1.8.0 Mar 19, 2024
@timostamm
Copy link
Member

Hey Azuka, the initializer does not accept string values for enum. I'd expect a type error in your call:

const list = new ProjectServiceListRequest({sort: 'PROJECT_SORT_JOB_NUMBER'});
                                                  ^ TS2322: Type string is not assignable to type ProjectSort

v1.7.2 and earlier let the string value through if the type error is ignored, and they use it as is for JSON, without a runtime check.

It is correct that the behavior for this usage is broken with v1.8.0, which adds an assertion. But I'm afraid it never was supported behavior. It may have worked in this specific situation, but only by accident, and you will run into undefined behavior in other places when ignoring the type error when constructing the message.

We'll try to find a better solution for this use case, but going through proto3.getEnumType is the correct solution for now. Alternatively, you could also use field info (see #738).

@Azuka
Copy link
Author

Azuka commented Mar 19, 2024

@timostamm thanks. I didn't realize that was incorrect behavior.

I've been using the enum string values in drop downs (because they're easier to read and troubleshoot than numbers).

@Azuka Azuka closed this as completed Mar 19, 2024
@timostamm
Copy link
Member

Yes, numeric enums are not ideal for this case. But you can use the names of the generated enum. For example, with this Protobuf enum (source):

enum PrefixEnum {
  PREFIX_ENUM_ZERO = 0;
  PREFIX_ENUM_ONE = 1;
}

The generated TypeScript enum is:

export enum PrefixEnum {
  ZERO = 0,
  ONE = 1,
}

TypeScript enums allow lookup from string or from number, and we can get a type for the string names with keyof typeof:

const names: keyof typeof PrefixEnum = ["ZERO", "ONE"];

There are several ways to get the string values for the array, but getEnumType is quite simple:

const names = proto3.getEnumType(PrefixEnum).values
  .map(v => v.localName) as (keyof typeof PrefixEnum)[];

You can use these names to populate a drop-down.

Then to set the value on the Protobuf message, you can convert the string name to the numerical value using the enum:

const selectedName = names[0];
myMessage.enumField = PrefixEnum[selectedName];

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants