-
Notifications
You must be signed in to change notification settings - Fork 38
Conversation
Hey @mattdamon108 normally |
In general, would you ask for feedback in the forum, as chances there are people who have thought about this already. |
@cristianoc Yes, it is. The ppx has no access to it either. But I'd like to add the functionality to access the module which exists in the same file.
Sure thing, thanks. |
Thank you for your work. I have something to suggest. Is it possible to output the following when there is an input like the following? input: <input type=text {...register("name")} /> output: React.cloneElement(
ReactDOMRe.createDOMElementVariadic("input", ~props=ReactDOMRe.domProps(~type_="text", ()), []),
register("name"),
) What I would suggest is to use the expression as-is. This means automating the use of cloneElement. Or does anyone have a better idea? |
10d7dec rebase and force-pushed due to pulling the recent commits from master. Build with dune 🥇👍 |
@mattdamon108 to continue the discussion about implementation, this looks like a feature that needs type (hence scope) information. Not sure if this is something you would like to explore. Likely it will need to be explored during a longer time frame. |
Also it might be useful to focus on examples that cannot be equivalently done with a function. type pr = {
sizes: string,
srcDoc: string,
}
let baz = {
sizes: "ReScript",
srcDoc: "Awesome",
}
@react.component
let make = () => {
let mkDiv = (~id, ~props as {sizes, srcDoc}, ~children) =>
<div id onClick={_ => ()} sizes srcDoc> children </div>
<>
{mkDiv(~id="1", ~props=baz, ~children=React.string("ab"))}
{mkDiv(~id="2", ~props=baz, ~children=React.string("cd"))}
</>
} |
or as @react.component
let make = () => {
module Div = {
@react.component
let make = (~id, ~props as {sizes, srcDoc}, ~children) =>
<div id onClick={_ => ()} sizes srcDoc> children </div>
}
<>
<Div id="1" props=baz> {"ab"->React.string} </Div>
<Div id="2" props=baz> {"cd"->React.string} </Div>
</>
} The language offers already a lot of abbreviation mechanisms, so it might be good to explore what are examples that cannot be expressed this way. |
@cristianoc That would be alternatives at this moment without syntax support and instead of this PR. But actually, the point is spreading by language, not by the user. For example, @react.component
let make = () => {
let { register } = ReactHookForm.use() // register: string => {onChange, onBlur, ref, ... }
<input id="1" {...register("name")} />
} I know that this PR can't solve this use case but, my ultimate intention is to solve this use case with syntax support. I think this feature will embrace more Js users and helps a lot to interop the Js modules. I agree that this can't be resolved with an untyped parse tree. I already encountered several times during making the ppxes. I want to explore the journey to resolve this syntax support if the core team has willing to adopt this language feature in future. Anyway, can you give a clue on how to access the expression or type after making typedtree? How to traverse the all merged typedtrees from one to another? I'm reading the reanalyze to search for a clue, but no gain so far. I'm still learning and not sure what actually the flambda and lambda IR is, but is it possible to spread in that step? |
In this example, what's the type of As of possible ways forward, it seems likely that advancing this #521 would be a stepping stone towards this. |
In my example, the type of type t = {
onChange: ReactEvent.Form.t => unit,
onBlur: ReactEvent.Focus.t => unit,
ref: ReactDOM.domRef,
name: string,
}
let register: string => t |
OK then I think this feature will come for free with #521 |
I got your point. If the jsx is parsed to the normal function and passes the object as arguments based on the more general structural typing (case no. 1), I agree that it is the first step to advance to make happen. But I'm still unclear about case no. 2, how to make structurally typing this multiple arguments layer? @react.component
let make = () => {
let { register } = ReactHookForm.use()
// case 1. OK
// just parse it to ReactDOMRe.createDOMElementVariadic("input", ~props=register("name"))
<input {...register("name")} />
// case 2. unclear
// {"id": string, "type_": string} and {"onChange": ... , "onBlur": ... , "ref": ..., "name": string }
<input id="1" type_="button" {...register("name")} />
} |
That only requires record spread, which is part of the language. |
Wow, I've verified this just moment ago. type foo = {name: string}
let foo = {
name: "woonki",
}
let foo1 = foo
type bar = {
name: string,
age: int,
}
let bar = {...foo1, age: 10}
|
I got your point again. the more general structural typing and the immutable updated record will solve cases 1, 2! I think it needs to change the jsx mapper either. Can I ask how the progress is going? I think I can contribute to making up for this PR further. |
There's no work except for the little text written in the issues. |
Got it with thanks! I'm gonna work on this PR and let you guys know. |
First, test the new record types' functionality. Solving the error message issue is also useful. |
Checked, good to know that! |
@cristianoc I've implemented the spread props feature with the general type checking of the structural typings. https://forum.rescript-lang.org/t/rfc-more-general-type-checking-for-structural-typings/1485/73 This is quite a visible change behind the jsx definition. This PR will change how to define the // as-is
@obj external makeProps: (~key: string=?, unit) => {.} = ""
let make = () => {
ReactDOMRe.createElement(
ReasonReact.fragment,
[
React.createElement(
Foo.make,
Foo.makeProps(~id="2", ~onClick={_ => ()}, ~children={`Foo`->React.string}, ()),
),
],
)
} // to-be
@obj
type makeProps = {
key: option<string>,
}
let makeProps = (props: makeProps) => props
let make = () => {
ReactDOMRe.createElement(
ReasonReact.fragment,
[
React.createElement(
Foo.make,
Foo.makeProps({id: "2", onClick: _ => (), children: {`Foo`->React.string}}),
),
],
)
} I well acknowledge that this RFC needs more tests and polishing rescript-lang/rescript#5412, but I hope this PR could be one of the good samples and tests for the RFC as well. |
spread props module Foo = {
@obj
type makeProps<'id, 'onClick, 'onBlur, 'children> = {
key: option<string>,
id: 'id,
onClick: 'onClick,
onBlur: 'onBlur,
children: 'children,
}
let makeProps = (props: makeProps) => props
let make =
(
@warning("-16") ~id,
@warning("-16") ~onClick,
@warning("-16") ~onBlur,
@warning("-16") ~children,
) => {
ReactDOMRe.createDOMElementVariadic("div", [{`Foo`->React.string}])
}
}
@obj
type makeProps = {
key: option<string>,
}
let makeProps = (props: makeProps) => props
let make = () => {
ReactDOMRe.createElement(
ReasonReact.fragment,
[
ReactDOMRe.createDOMElementVariadic(
"div",
~props={...foo, id: "1", onClick: _ => ()},
[{`div`->React.string}],
),
React.createElement(
Foo.make,
Foo.makeProps({...foo, id: "2", onClick: _ => (), children: {`Foo`->React.string}}),
),
],
)
} |
@mattdamon108 how about adding the corresponding pr in the compiler repo, which uses this as syntax, and shows a few compiled examples with their generated code. One of the questions is whether makeProps is still needed. Can one do without? |
Also it might be best to start with simple examples, rather than the new spread, which is a more advanced case. Also, this should probably be called ppx version 4. For the purpose of gradual upgrade the two need to at least co-exist. In addition, one should see if that is enough for a v4 project using v3 dependencies. |
Agree.
I had the same question, but I think it is still needed because it has a role to check the type of props in the record, unless we are designing the |
And plus, React.createElement(
type,
[props],
[...children]
) |
Yes, the idea is to illustrate the new mechanism with simpler examples first, then the prop spread comes later (in the description), as an advanced example. The implementation can cover all at once, does not matter. Notice the previous work on this: #235 |
only show how to transform the arrow function.
I missed adding test files, then I found that some tests failed after pushing the commits. 1c185ed I'll fix it. |
I have an idea to generate the proper output for |
It does not need to literally change the ast. It can be just a guide on how to structure the implementation. |
The spec indicates what is the result of the transformation, it does not impose a specific way to implement it. |
Oh I misunderstood your intention. I thought the changing ast will be more cleaner desgin, but I found it is not. 🥲 |
I'll reset the latest 2 commits, then I'll fix the |
I have renamed this PR. |
OK I'll make a new PR |
Closed. Further discussion in #547 |
Hi, team!
I'd like to convey my sincere appreciation for your hard work and contributions as a big fan of ReScript.
This PR adds the syntax support for JSX spread props such as below. I'm not sure whether the contribution from others besides the core team is open or not. But I think this feature will help many jsx use cases easier and cleaner. I didn't write the test yet, but please let me know and have a guide to writing a test for this case.
It is parsed and extended to