gpt4 book ai didi

scala - 为 API 包装器实例化 js.Object 的建议方法是什么

转载 作者:行者123 更新时间:2023-12-01 01:00:46 24 4
gpt4 key购买 nike

对于以下 javascript API 包装器:

@JSName("React")
object React extends js.Object {
def createClass(init: ReactClassInit): ReactClassBuilder = ???
}

建议什么来实例化以下特征
trait ReactClassInit extends js.Object {
val render: js.ThisFunction0[js.Dynamic, js.Any]
}

目前我正在做以下事情:
val * = js.Dynamic.literal
val init = *(render = new js.ThisFunction0[js.Dynamic, js.Any] {
override def apply(thisArg: js.Dynamic): js.Any = {
React.DOM.div(null, "Hello ", thisArg.props.name)
}
}).asInstanceOf[ReactClassInit]
val HelloMessage = React.createClass(init)

我不喜欢这种方法的一点是没有类型安全
确保 ReactClassInit 正确实例化。

(这是将事情置于更好的上下文中的所有代码)
//Work in progress React wrapers
@JSName("React")
object React extends js.Object {
def createClass(init: ReactClassInit): ReactClassBuilder = ???
def renderComponent(cls: ReactClassInstance, mountNode: HTMLElement) = ???
val DOM: ReactDOM = ???
}

trait ReactDOM extends js.Object {
def div(huh: js.Any, something: js.String, propsOrWhat: js.Any) = ???
}

trait ReactClassInstance extends js.Object

trait ReactClassBuilder extends js.Object {
def apply(args: js.Object): ReactClassInstance
}

trait ReactClassInit extends js.Object {
val render: js.ThisFunction0[js.Dynamic, js.Any]
}



@JSExport
object ReactTodo {
//Some helpers I use.
val * = js.Dynamic.literal

@JSExport
def main() {
helloJonT()
}


//Ideal Typed Example
def helloJonT() {
val init = *(render = new js.ThisFunction0[js.Dynamic, js.Any] {
override def apply(thisArg: js.Dynamic): js.Any = {
React.DOM.div(null, "Hello ", thisArg.props.name)
}
}).asInstanceOf[ReactClassInit]
val HelloMessage = React.createClass(init)
React.renderComponent(HelloMessage(*(name = "Jon").asInstanceOf[js.Object]), document.getElementById("content"))
}

}

最佳答案

目前,推荐的方法与您正在做的非常接近,除了使用 js.Dynamic.literal应该封装在您的特征的伴随对象中(在您的情况下为 ReactClassInit)。您可以提供类型安全的 apply该伴随对象中的方法如下:

trait ReactClassInit extends js.Object {
val render: js.ThisFunction0[js.Dynamic, js.Any]
}
object ReactClassInit {
def apply(render: js.ThisFunction0[js.Dynamic, js.Any]): ReactClassInit = {
js.Dynamic.literal(
render = render
).asInstanceOf[ReactClassInit]
}
}

然后您可以将其用于:
val init = ReactClassInit(render = { (thisArg: js.Dynamic) =>
React.DOM.div(null, "Hello ", thisArg.props.name)
})

当然,这仍然是全局不安全的。但是在您的代码中只有一处使用了强制转换,更重要的是它接近类型的定义。因此,如果您更新一个,则更有可能更新另一个。

我知道这不是一个完全令人满意的解决方案。但是到目前为止,在我们的 Scala.js 设计中,我们还没有找到一个很好的解决这个问题的方法。

两个边注:

1) 我 强烈反对 使用 new js.ThisFunctionN { def apply } !这种表示法完全起作用纯属意外。只需使用我在示例中展示的 lambda。如果目标类型输入为 js.ThisFunctionN已经(就像在我的代码中一样),它会像那样工作。如果,就像你的代码一样,目标类型是 js.Any (或 Any ),您需要将您的 lambda 归因于 : js.ThisFunction (不带数字)以确保编译器将其视为此函数而不是(非此)函数,仅此而已。为了更清楚,以下是您的代码的外观:
val init = *(render = { (thisArg: js.Dynamic) =>
React.DOM.div(null, "Hello ", thisArg.props.name)
}: js.ThisFunction).asInstanceOf[ReactClassInit]

2) 你可能希望你的函数被输入为返回 Any (或 _ )而不是 js.Any :
trait ReactClassInit extends js.Object {
val render: js.ThisFunction0[js.Dynamic, Any]
}

通常当您使用 js.Any 时在 js.(This)Function 的结果类型中,你的意思是任何值,而不是任何 JS 值。 Scala 的类型推断最适用于 Any在那个位置。

关于scala - 为 API 包装器实例化 js.Object 的建议方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23663059/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com