Search code examples
javascriptscala.jsbinding.scala

Access nested property of JS Object in ScalaJS


i am trying to access a property which is available in deep inside of an object. How to do this in scala js type safe way?

internetMessageId property is available on Office object which is accessible in plain javascript in below way :

Office.context.mailbox.item.internetMessageId

My scala JS facade of Office object :

@js.native
@JSGlobal
object Office extends js.Object {
  var initialize:js.Function1[String, _] = js.native
}

How to write access method for property internetMessageId on Office object in ScalaJs?


Solution

  • Well, internetMessageId is not a property of Office. Office needs to have property cotnext, for which you define a @js.native trait Context facade, which should have a property mailbox, for which you define a @js.native trait Context facade, and so on until you get to @js.native trait Item which finally defines a property internetMessageId.

    Example trait code for this hierarchy:

    @js.native
    trait Context extends js.Object {
      val mailbox: Mailbox = js.native
    }
    

    Then Office.context.mailbox.item.internetMessageId will actually be valid, type-checked Scala code.

    However, remember that when defining such @js.native facades the Scala compiler assumes that you have defined them correctly. So if you have e.g. misspelled context like I did in the first paragraph, your code will fail at runtime. So your type safety is as good as your facades are.

    So, if you only need to access this one field out of the whole nested structure, you can save time by just defining some getInternetMessageId method somewhere, which would access the deeply nested field in a non-typesafe way, using js.Dynamic. It would look kinda weird and ad-hoc, but that's because it is. But it would not be less type safe.

    My point is, that you will have to contain "type-unsafety" somewhere when dealing with JS-provided objects. It's best to contain it within the facades (option 1), but sometimes that's too much overhead.