Is Type Parameter limited

https://rescript-lang.org/try?code=C4TwDgpgBAThDGUB2B7AJhAglAvFA3mAIZxLABcUKYwAlikgDyoaYB8ANFEZbWQL4AoQaEiwEydBABCuAsVIUqNekxYzOUAEa8BwgDYRgUAOZGACiQhk5ACnWUA5EQCUuNpIwA6BdeAGjT2g8QisySgA5BgguHigARiFDYzgAZwBXfWM8M2BLRXspF0EgA

see this demo. I can’t write common tree utils with Type Parameter

1 Like

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)

Playground Link

Major downside of this approach is that whenever you have a type mismatch, you will get less actionable type check errors (comparable to TS).

4 Likes

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.

1 Like

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.

3 Likes

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

3 Likes