Any record type


from time to time I need a function, which accepts any records.
Here is an example:

let getKeysOfRecord = record => {

type test1 = {
  foo: string,
  bar: string,
  baz: int,

type test2 = {
  x: int,
  y: int,

These function calls will work:

testToDict->getKeysOfRecord({foo: "hello", bar: "world", baz: 1})->Console.log
testToDict->getKeysOfRecord({x: 1, y: 2})->Console.log

Unfortunately I could also pass anything else:

getKeysOfRecord("hello world")->Console.log

I know, I could also use objects, but I don’t like them:

let getKeysOfRecord = (record: {..}) => {

getKeysOfRecord({"foo": "hello", "bar": "world", "baz": 1})->Console.log

Or I get rid of the Obj.magic, by creating converters for my records:

let getKeysOfRecord = record => {

external test1ToDict: test1 => Dict.t<'a> = "%identity"
external test2ToDict: test2 => Dict.t<'a> = "%identity"

test1ToDict({foo: "hello", bar: "world", baz: 1})->getKeysOfRecord->Console.log

Would it be feasible and possible to have a syntax for all record types?

let getKeysOfRecord = (record: {|..|}) => {


sorry not a full response but have you considered a binding for Object.keys instead of toDict->Keys?

external keys: 'a => array<string> = "Object.keys"

Didn’t consider this solution but unfortunately the same problem: 'a could be everything :frowning:

the same problem? seems like at least two:

  1. get the keys from any record type
  2. do not get the keys from types that are not records

anyway struck me that this is a very sound function since the Js is pretty complete…Object.keys(3) = [], as youd expect, Object.keys([1,2]) = [“1”, “2”]

The Problem you are facing is “nominal” vs “structural” typing:

  • records are nominal typed in rescript:
    type equality is only given if the name of two types are the same (optimally after resolving some aliases)
  • objects & modules are structural typed
    • two types are equivalent if they are of the same “shape”

This means, there is currently no way to express a type of “any record” in rescript.

Therefore the only solutions have been mentioned already:

  1. convert records to some common type (probably by an identity external)
  2. use objects (or any other structural type)
  3. use a function which holds it’s invariants for any given type

One of ReScript’s stated goals is to get away from the complex types used to model highly dynamic JS programming patterns, and encourage simpler static patterns. So I doubt that the ‘any record’ type would be possible. In this particular example it really seems like the simplest and safest approach would be to manually define a toDict function for the record type to convert it into a Js.Dict.t<_>. This is conceptually similar to defining a JSON codec, and at scale we can imagine that a codegen or PPX approach could help do it automatically for us just by annotating the record type.


Well, the reason I like rescript more then typescript is the simplicity.
Before it turns to a bloated and complex type system, I agree with you.

While I’m still a bit afraid of PPXs, I should consider to use them for some purposes.

Thanks all of you.