Thanks for the sanity check. I think that I was overthinking this.
I was wondering if variant types might not be the right thing to use here, but it sounds like it is. Your suggestion to write a mapping functions is the right way to go.
You asked what I’m trying to model. It’s a Reason React app, featuring a series of questions. Each question has some text, and an input type. The input type is either text field or a checkbox. The user interacts with it and the result is either text or a bool, depending.
type userInput =
| Bool(option(bool))
| Text(option(string));
type question = {
text: string,
userInput: userInput
};
let makeQuestion = (text, userInput) => {
{text, userInput};
};
let makeInputField = (question: question) => {
switch (question.userInput) {
| Text(initialVal) =>
let htmlElement = .../* text input box */;
let inputFieldValue = /* text which user typed in */;
(htmlElement, inputFieldValue);
| Bool(_) =>
let htmlElement = ... /* checkbox */ ;
let inputFieldValue = /* the contents of the checkbox, true/false */;
(htmlElement, inputFieldValue);
};
};
When I call makeInputField, I get back the HTML element to render, and a inputFieldValue of type userInput, which is either Bool(option(bool)) or Text(option(string)), with the contents of the user’s response after they interact with that input.
I wanted an easy way to get the wrapped value, which is a bool or a string. I can just write a mapping function with some reasonable false-ish values. Something like this:
let getUserInputStr = (inputFieldValue) => {
switch(inputFieldValue){
| Text(Some(str)) => str
| _ => ""
}
}
let getUserInputBool = (inputFieldValue) => {
switch(inputFieldValue){
| Bool(Some(b)) => b
| _ => false
}
}