scala – 为API包装器实例化js.Object的建议方法是什么
对于以下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) 我不喜欢这种方法是没有类型安全 (以下是将事物置于更好的上下文中的所有代码) //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,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).您可以在该伴随对象中提供类型安全的应用方法,如下所示:
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,thisArg.props.name) }) 当然,这仍然是全球不安全的.但是在代码中只有一点使用强制转换,更重要的是它接近于类型的定义.因此,如果您更新一个,则更有可能更新另一个. 我知道这不是一个完全令人满意的解决方案.但到目前为止,在我们的Scala.js设计中,我们还没有找到一个非常好的解决方案来解决这个问题. 两个旁注: 1)我强烈建议不要使用新的js.ThisFunctionN {def apply}!这种符号完全奏效是一个意外.简单地使用我在我的例子中展示的lambda.如果目标类型已经被输入为js.ThisFunctionN(就像在我的代码中那样),它就会像那样工作.如果,如代码中的情况,目标类型是js.Any(或Any),则需要将lambda归为:js.ThisFunction(不带数字),以确保编译器将其视为此-function而不是(非this-)函数,但这就是全部.为了更清楚,以下是您的代码看起来如何: val init = *(render = { (thisArg: js.Dynamic) => React.DOM.div(null,thisArg.props.name) }: js.ThisFunction).asInstanceOf[ReactClassInit] 2)你可能希望你的函数被输入为返回Any(或_)而不是js.Any: trait ReactClassInit extends js.Object { val render: js.ThisFunction0[js.Dynamic,Any] } 通常,当你在js.(This)函数的结果类型中使用js.Any时,你的意思是任何值,而不是任何JS值. Scala的类型推断最适合在该位置使用Any. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |