For my UI component library, I'm adding support for props, using the builder pattern (so the user doesn't have to specify all the fields).
And I'm trying to use the phantom types, because they seem cool, but with a slight modification.
Here's an example:
pub type NoOnInput =
Nil
pub type OnInput(msg) =
fn(TextState) -> msg
pub type NoValue =
Nil
pub type Value = String
pub type TextProps(on_input, value) {
TextProps(
on_input: on_input,
type_: String,
placeholder: option.Option(String),
value: value,
)
}
pub fn init() -> TextProps(NoOnInput,NoValue) {
TextProps(on_input: Nil, type_: "text", placeholder: option.None, value: Nil)
}
pub fn with_value(props: TextProps(i, NoValue), value: Value) -> TextProps(i, Value) {
TextProps(
on_input: props.on_input,
type_: props.type_,
placeholder: props.placeholder,
value: value,
)
}
pub fn build(props: TextProps(OnInput,Value) {
// here the type checker knows that oninput and value are not Nil
}
As you can see, the types are not that phantom, because I actually use them in the record. I think it's better that way, because then I don't have to do any asserts or anything.
But I've seen people not do that. So here's the first question: is there a reason to use actual phantom types, instead of whatever-it-is-im-doing?
Second thing: I see that we can't use record spreading if the input record is of a different type. Which makes sense for most cases, but I feel like in this case it's not an useful limitation (and even more so when using actual phantom types).
Is there a reason for this behaviour? Or is it just a limitation of the current type checker and I can expect it to be fixed SomeDay™?