Coming from TypeScript, I was wondering if there was a way to guarantee that a generic should include certain data with something like a generic constraint.
function foo<T extends {a: string}>(x: T) {
console.log(x.a)
}
// good
foo({a: '', b: '3'})
// error
foo({b: '3'})
tsnobip
September 14, 2021, 7:36am
2
Rescript allows you do that thanks to the structural typing of objects :
let f = x => Js.log(x["a"])
ryyppy
September 14, 2021, 7:50am
3
As @tsnobip said, you’d need structural typing for that.
To get a sense for type signatures, here’s an example that allows only values that at least have a {"a": string}
within an object type:
let foo = (x: {.."a": string}) => {
let str = x["a"] ++ " world"
Js.log(str)
}
foo({"a": "hello", "b": "test"})
foo({"a": "hello", "c": "test"})
// This has type: {"b": string}
// Somewhere wanted: {.."a": string}
foo({"b": "test"})
Playground Link
Unfortunately subtyping is not documented yet. {..
denotes an “open structural object type”.
If you’d want to pull out the type definition for your parameter, it would look a little different:
type mySuperType<'a> = {.."a": string} as 'a
This declaration tells the compiler that this type should at least contain "a": string
within its definition. We need the 'a
placeholder for subtypes:
type sub = mySuperType<{"a": string, "b": string}>
let a: sub = {"a": "test", "b": "test"}
Here, we make a concrete subtype that requires you to provide the "a": string
, otherwise the compiler would error out.
8 Likes
this is great, thank you!