Scala.js js.Dynamic 用法导致递归无限数据结构

Scala.js js.Dynamic usage leads to a recursively infinite data structure

我正在尝试使用 Google Visualizations from Scala.js. I generated the type definitions using TS importer,它生成的相关部分是:

@js.native
trait ColumnChartOptions extends js.Object {
  var aggregationTarget: String = js.native
  var animation: TransitionAnimation = js.native
  var annotations: ChartAnnotations = js.native
  // ... more
}

@js.native
trait TransitionAnimation extends js.Object {
  var duration: Double = js.native
  var easing: String = js.native
  var startup: Boolean = js.native
}

现在,我想弄清楚如何实际使用它并提出:

val options = js.Dynamic.literal.asInstanceOf[ColumnChartOptions]
options.animation = js.Dynamic.literal.asInstanceOf[TransitionAnimation] // comment this and the next line and chart will appear
options.animation.duration = 2000
options.title = "Test Chart"
options.width = 400
options.height = 300

如果我没有设置动画设置,这会起作用,但如果我设置了,就会失败,图表显示 "Maximum call stack size exceeded"。

我调试了一下,发现如下:

所以 animation 包含对自身的引用,但根据上面的代码,我认为这不应该发生。

想法如何解决?

关于如何最好地使用生成的类型以提供类型安全的方式来创建 Google Visualizations 期望的 JavaScript 对象的任何其他建议?我尝试了 new ColumnChartOptions {},它看起来比 js.Dynamic 更干净,但失败了 "A Scala.js-defined JS class cannot directly extend a native JS trait."

P.S。我想指出

options.animation = js.Dynamic.literal(
  easing = "inAndOut",
  startup = true,
  duration = 2000
).asInstanceOf[TransitionAnimation]

实际上有效,但不是类型安全的(durationdurration 的拼写错误不会被发现)。

您的代码在调用 literal() 时缺少 (),因此解决方法是:

val options = js.Dynamic.literal().asInstanceOf[ColumnChartOptions]
options.animation = js.Dynamic.literal().asInstanceOf[TransitionAnimation] // comment this and the next line and chart will appear

在 Scala 中(因此在 Scala.js 中),() 的存在与否有时是有意义的。 literal 是单例 object literal,而 literal() 调用所述对象的方法 apply()