Loop / Map / Iterate Record type itself (not the instance)


#1

Hi there!

Let’s say I have a simple Record type like this:

type message = {
  id: int,
  tags: option(array(string)),
  body: option(string),
};

Is it possible to iterate (map or loop) over each field of the message type itself (not the instance).

I have a function that should take a record type (e.g. message) as an argument and then create a HTML dropdown list depending on the record field names and their types. Practically this means I need to iterate over each filed and pattern match the types for each of them.

Does anyone how this could be done? :slight_smile:


#2

This is the kind of thing that makes sense in JavaScript, but doesn’t really make sense in Reason. At run time, the names of the attributes don’t actually exist, and they’re definitely not accessible to runtime code. And if you could, what would the type of that mapper function be?
There are a couple of ways to get around this (techniques for generating the code for each field), but by far the simplest solution is to just write the code yourself for each field. :woman_shrugging:


#3

@jaredly Thanks for your reply!

but by far the simplest solution is to just write the code yourself for each field.

I usually would do that, but the module I’m currently writing is a form generator. It should take some instruction from the consumer (e.g. the message record) and generates a form from it. I thought the simplest and cleanest solution might be to just pass the Record type definition directly to the form generator, because the form generator needs to know about the field-name and the field-type, and that’s right there in the type definition.

I’m wondering, what would be a good way to pass the field-names and filed-types to the generator function? Perhaps I need to create a “dummy” instance of the Record type and pass it to the generator function? E.g.:

let myMessage = {
  id: 1,
  tags: [|"foo"|],
  body: "foo",
};

/* later */

    <div className="my-form">
        (FormGenerator.renderFrom(myMessage)
    </div>
 

I’m very new to ReasonML, please bear with me :slight_smile:


#4

The thing is, the type definition doesn’t exist at runtime. So you can’t do any logic with it.
What I have done in similar situations is have the user pass in both the object and a list of fields.
e.g.

let formFields = [
  (message, onChange) => <IntField value={message.id} onChange={id => onChange({...message, id}) />,
  (message, onChange) => <StringField value={message.body} onChange={body => onChange({...message, body}) />,
];
let renderMessageForm = FormGenerator.renderForm(formFields);

/* later */

    <div className="my-form">
        (renderMessageForm(myMessage)
    </div>