see this demo. I can’t write common tree utils with Type Parameter
I suspect you may need to do something like this:
type value = ValueA(int) | ValueB(int)
type rec node = {parent: option<node>, value: value}
let getParent = node => node.parent
let node = {parent: None, value: ValueA(1)}
let result = getParent(node)
In the playground code, the parent property has two different types.
In this code, the parent property has single type.
Since there are some ambiguities in the function defnitions
let getParent = (node: nodeA) => node.parent
Adding a type annotation fix the issue
no, I want this function work on subset of typing, so it suit for both nodeA and nodeB
Records are nominal (correspond to a particular type), not structural (correspond to particular shape), so you can’t do that.
You’d need to switch to structural objects, like here:
type rec nodeA = {"parent": option<nodeA>, "a": int}
type rec nodeB = {"parent": option<nodeB>, "b": int}
let getParent = (node: 'a) => node["parent"]
let node = {"parent": None, "a": 1}
let result = getParent(node)
let nodeB = {"parent": None, "b": 1}
let result2 = getParent(nodeB)
Major downside of this approach is that whenever you have a type mismatch, you will get less actionable type check errors (comparable to TS).
I wonder if there’s something like Elm’s extensible record system for ReScript?
Where you can do something like
Foo : { name : String | t } -> String
Foo bar = bar.name
And then you can pass any record that has a name
field that is a String to this function.
If not, do you think that could be a good addition to the language? Seems pretty useful
Edit: nevermind, just saw that @ryyppy’s comment above does exactly the same, but using structural objects.
Because this is indeed structural, which is the default for records in elm if I’m not mistaken.
Structural typing often looks like a good idea, but in practice, less explicit error messages and no pattern matching make it a much less appealing approach compares to nominal typing for records.
You can do this with objects and constraints (not a 100% equivalent thing)
type userLike<'a> = {.."name": string} as 'a
let extractName: userLike<_> => string = user => user["name"]
let name = extractName({"name": "John", "age": 20})
let name' = extractName({"name": "John", "age": 20, "username": "siever"})
let name'' = extractName({"age": 20, "username": "siever"}) // type error shuold have "name" field