Hi guys.After I had defined es Proxy, when I was calling it, a compilation failure occurred.
The rescript source code:
type t
@new external proxy: ('a, 'b) => t = "Proxy"
let p = proxy(
() => ignore()
, {
"get": (_, p) =>
if p === "hello" {
Js.log("Hello Rescript!!!")
}
}
)
p.hello
Compiled js code:
var p = new Proxy((function (param) {
}), {
get: (function (param, p) {
if (p === "hello") {
console.log("Hello Rescript!!!");
return ;
}
})
});
p.hello // Manual compilation line
export {
p ,
}
The error is reported below:
rescript: [3/3] src/index.cmj
FAILED: src/index.cmj
We've found a bug for you!
/root/rescript/rescript/src/index.res:14:3-7
12 │ )
13 │
14 │ p.hello
15 │
The record field hello can't be found.
If it's defined in another module or file, bring it into scope by:
- Prefixing it with said module name: TheModule.hello
- Or specifying its type: let theValue: TheModule.theType = {hello: VALUE}
FAILED: cannot make progress due to previous errors.
ERROR Command failed with exit code 2.
After manual compilation, used deno to run js code:
>> deno run -A ./lib/es6/src/index.js
$ Hello Rescript!!!
So, how to deal with this situation?
There are probably quite a few ways to do this, but I suspect you might need to use some concrete types. Here’s an idea, but others might be able to suggest improvements.
module Proxy = {
@new external make: ('a, 'b) => 'c = "Proxy"
}
module Person = {
type person = {name: string}
type personWithGreeting = {name: string, greeting: string}
let greetingHandler = {
"get": (person: person, prop: string): string => {
if prop == "greeting" {
"Hello " ++ person.name
} else {
%raw(`Reflect.get(...arguments)`)
}
},
}
let withGreeting = (p: person): personWithGreeting => Proxy.make(p, greetingHandler)
}
let p1: Person.person = {name: "Earth"}
let p2: Person.personWithGreeting = Person.withGreeting(p1)
Js.log(p1.name) // Earth
Js.log(p2.name) // Earth
Js.log(p2.greeting) // Hello Earth
At first, thank you for the explaining code. I understand that the display has a certain fixed attribute (such as ‘greeting’) under the specified type and can be compiled. If a certain attribute member is not fixed, how to deal with it. Forgive my broken English, I don’t know if I express it clearly。Just like
rs Code:
Js.log(p2.tom)
will print
$ "Hello Tom"
rs Code:
Js.log(p2.john)
will print
$ "Hello John"
You don’t know which method will be called by user. The method name is used as a dynamic variable in the “Proxy” instance like a function parameter.
At the end, thank you again for your help.
Hi @footearth can you provide some example JS code that shows what you are trying to achieve? That will help with finding a solution.
However, here’s another example that uses JS object types instead of record types:
module Proxy = {
@new external make: ({..}, {..}) => {..} = "Proxy"
}
let o = Proxy.make(
Js.Obj.empty(),
{
"get": (_target: {..}, prop: string) => {
if prop == "hello" {
"Hello ReScript"
} else {
%raw(`Reflect.get(...arguments)`)
}
},
},
)
// values have unknown types
let value1 = o["hello"]
let value2 = o["world"]
Js.log(value1) // Hello ReScript
Js.log(value2) // undefined
Thanks @kevanstannard. This is exactly what I need.
My usage scenario is to use “Proxy” to proxy React.jsx
Simple JS code like this:
const { div, p, li } = new Proxy(
{}
, {
get: (t, tagName) =>
(attr, children) => React.jsx(tagName, attr, children)
}
)
I suspect the challenge you will face here is the arbitrary destructuring to the different tags.
An idea that’s less dynamic but may have a similar syntax to your example would be to declare a module with each of the tags you are interested in.
For example:
module ReactElement = {
let make = (
name: string,
props: ReactDOM.domProps,
children: array<React.element>,
): React.element => {
React.createElementVariadic(ReactDOM.stringToComponent(name), props, children)
}
let div = make("div")
let p = make("p")
let li = make("li")
}
And then you might use it like this:
let {div, p, li} = module(ReactElement)
let el = div(
ReactDOM.domProps(~id="test", ~className="someclass", ()),
[
p(ReactDOM.domProps(), [React.string("Hello")]),
p(ReactDOM.domProps(), [React.string("World")]),
],
)
Someone else might be able to suggest a better idea that uses your Proxy suggestion.