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

Get T property of FieldInfo #738

Closed
nicole0707 opened this issue Mar 6, 2024 · 4 comments
Closed

Get T property of FieldInfo #738

nicole0707 opened this issue Mar 6, 2024 · 4 comments

Comments

@nicole0707
Copy link

I am experimenting to retrieve values of enum FieldInfo, is there any existing API to get that? Otherwise, is it possible to export fiPartialRules<fiScalar> | fiPartialRules<fiEnum> | fiPartialRules<fiMessage> | fiPartialRules<fiMap> types for us? Thanks!

{
    kind: 'enum',
    no: 8,
    name: 'repayment_type',
    jsonName: 'repaymentType',
    T: {
      typeName: 'test.id.RepaymentType',
      values: [Array],
      findName: [Function: findName],
      findNumber: [Function: findNumber]
    },
    opt: true,
    default: undefined,
    localName: 'repaymentType',
    repeated: false,
    packed: true
  }
@timostamm
Copy link
Member

Hey Nicole, Protobuf fields can be simple scalar values, but also message references, arrays (repeated field), or records (map fields).

The FieldInfo type represents all of them as a union, with the "kind" property as a discriminator. We don't export the individual types, only the union. In fact, we don't even define individual types internally, because using the union type with the discriminator is usually sufficient.

For example, we're walking through all fields here, and access the enum type for enum fields:

for (const fi of myMessage.getType().fields.list()) {
  if (fi.kind == "enum") {
    const enumType: EnumType = fi.T;
  }
}

The TypeScript compiler narrows down the FieldInfo union type with the check on the discriminator property, and knows that T is an EnumType inside the if block.

To refer to enum FieldInfo, you can use FieldInfo & {kind:"enum"}. For example, this function lists all enum fields:

function findEnumFields(messageType: MessageType) {
  const enumFields: (FieldInfo & {kind: "enum"})[] = [];
  for (const fi of messageType.fields.list()) {
    if (fi.kind == "enum") {
      enumFields.push(fi);
    }
  }
  return enumFields;
}

The result is an array of FieldInfo where T is guaranteed to refer to an EnumType.

We can take this one step further, to implement a function that finds an EnumType for a given field name:

function findEnum(messageType: MessageType, fieldName: string): EnumType | undefined {
  for (const fi of messageType.fields.list()) {
    if (fi.localName === fieldName) {
      if (fi.kind == "enum") {
        return fi.T;
      }
    }
  }
  return undefined;
}

Assuming you have a variable messageType: MessageType in scope, you would use it like this:

const enumType = findEnum(messageType, "myField");
if (enumType) {
  enumType.values;
}

Does this help?

@nicole0707
Copy link
Author

Thanks @timostamm , it's really useful!

@timostamm
Copy link
Member

Great, I'll close this 👍

Future versions might allow this to work with type-safe field names.

@timostamm
Copy link
Member

Type-safe conversion between an enum value and its JSON name is implemented in the upcoming v2 by #866.

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