Description
Motivation
JavaScript doesn't support labeled arguments, but ReScript does. So let add: (~a, ~b)
in ReScript compiled to function add(a, b)
, so the labels a
and b
cannot be referenced by the call site.
In JS/TS codebase it is common to use object destructuring for this (e.g. props in React components) Also called RORO pattern
Until v10, gentype created a runtime mapper for this. However, since v11 it no longer generates runtime mappers. In the long term, gentype shouldn't have any runtime (See #6196)
However, the runtime mapper for props is an important feature for interoperability not only with TypeScript but also with JavaScript codebases in general. There must be an alternative to completely removing the feature.
This proposal solves the problem by extending the @deriving
tag existing in the ReScript core.
Detailed Design
Basic
@genType
@deriving(params)
let add = (~a, ~b) => a + b
produces
type \"add$Params" = {
a: int,
b: int,
}
@genType
let \"add$with" = ({ a, b }: \"add$Params") => {
let add = add(~a, ~b)
add
}
This is only valid for functions with labeled arguments, and requires that the @genType
tag be duplicated if it exists.
High-order functions
@deriving(params)
can only be used on top-level functions. This is because new type bindings cannot be defined in a closure. Btw, user may want mappers for nested functions like:
@deriving(params)
let add = (~a, ~b) => {
(~c, ~d) => {
(e, f) => {
a + b + c + d + e + f
}
}
}
If the return type of the function annotated by @deriving(params)
is a function, then it should produces
type \"add$Params" = {
a: int,
b: int,
}
type \"add$Params$1" = {
c: int,
d: int,
}
@genType
let \"add$with" = ({ a, b }: \"add$Params") => {
let add = add(~a, ~b)
({ c, d }: \"add$Params$1") => {
let add = add(~c, ~b)
add
}
}
Deriving is applied in nested functions, but ends when it encounters a function with no labeled parameters.
Customizing definitions
User can customize derived typenames to make it more useful in TypeScript side.
@deriving({ params: "add(Props)" })
let add = (~a, ~b) => a + b
type \"Props" = {
a: int,
b: int,
}
let add = ({ a, b }: \"Props") => {
let add = add(~a, ~b)
add
}
Implementation
TBD
Metadata
Metadata
Assignees
Labels
Type
Projects
Status
Status