Say I have the following state:
type t('a) = {
foo: string,
value: 'a
};
type state = {
one: t(int),
two: t(float)
};
let state = {
one: {
foo: "One int",
value: 3
},
two: {
foo: "Two float",
value: 5.3
}
};
And I have a set of functions that operate on t
:
let setFoo = (t, foo) => { ...t, foo };
let setValue = (t, value) => { ...t, value };
I’d like to set up ReasonReact actions that can run a function on any value of type t
, rather than have a unique set of actions for each combination. In my real app I have a lot more values of t
, so this would quickly grow unwieldly.
My approach is to define a type for each value in state, used to determine which value in state should
be operated on. I can switch on that type to run the desired function on the relevant part of the state:
type stateKey = One | Two;
type action =
| SetFooOn(stateKey, string);
let handleState = (action, state) => {
switch (action) {
| SetFooOn(stateKey, value) => switch (stateKey) {
| One => { ...state, one: setFoo(state.one, value) }
| Two => { ...state, two: setFoo(state.two, value) }
}
};
};
handleState(SetFooOn(One, "Hello"));
handleState(SetFooOn(Two, "Goodbye"));
That works. But this approach doesn’t work for t.value
- the parameterized value.
type actionTwo('a) =
| SetValueOn(stateKey, 'a);
let handleStateTwo = (action, state) => {
switch (action) {
| SetValueOn(stateKey, value) => switch (stateKey) {
| One => { ...state, one: setValue(state.one, value) }
| Two => { ...state, two: setValue(state.two, value) }
}
};
};
handleStateTwo(SetValueOn(One, 3), state);
handleStateTwo(SetValueOn(Two, 6.23), state); /* doesn't work - compiler wants an int */
Coming from languages without type inference, I would expect the type of “value” could just be ignored and passed through - but of course then the compiler can’t guarantee that stateKey
and value
are compatible. handleStateTwo(SetValueOn(One, 3.7))
should not be let through as One is associated with t(int)
.
I’m a bit stumped on how to proceed - whether my issue is solvable, or perhaps I’m going about it in completely the wrong way to begin with?
Thanks for reading.