How can we use methods that expect an options obje...
# javascript
v
How can we use methods that expect an options object? For example I have included
@actions/http-client
and want to use
HttpClient().post(...
. The
...d.ts
has
Copy code
export interface IHeaders {
    [key: string]: any;
}
[...]
post(requestUrl: string, data: string, additionalHeaders?: ifm.IHeaders): Promise<ifm.IHttpClientResponse>;
Dukat made from that
Copy code
external interface IHeaders {
    @nativeGetter
    operator fun get(key: String): Any?
    @nativeSetter
    operator fun set(key: String, value: Any)
}
[...]
open fun post(requestUrl: String, data: String, additionalHeaders: IHeaders = definedExternally): Promise<IHttpClientResponse>
My first approach was basically naively following the IDE autocompletion which of course does not work (no additional headers set):
Copy code
val response = HttpClient().post(
        requestUrl = "<http://localhost:9999/api/GetFiles>",
        data = "type=ProductId&url=$productId",
        additionalHeaders = object : IHeaders {
            override fun get(key: String): Any? = when (key) {
                "Content-Type" -> "application/x-www-form-urlencoded"
                else -> null
            }

            override fun set(key: String, value: Any) = error("headers are read-only")
        }
).await()
My next try was to do what my guts suggested and made the compiler happy:
Copy code
val response = HttpClient().post(
        requestUrl = "<http://localhost:9999/api/GetFiles>",
        data = "type=ProductId&url=$productId",
        additionalHeaders = mapOf("Content-Type" to "application/x-www-form-urlencoded") as IHeaders
).await()
IJ complains about "Unchecked cast to external interface: Map<String, String> to IHeader" and it also does not work, but sends the additional headers
Copy code
_keys_up5z3z$_0: null
_values_6nw1f1$_0: null
_keys_qe2m0n$_0: null
_values_kxdlqh$_0: null
internalmap_uxhen5$_0: [object Object]
equality_vgh6cm$_0: [object Object]
_entries_7ih87x$_0: null
a
I’ve used the kotiln-wrappers library and then you build it like so:
Copy code
js {
  this["Content-Type"] = "text/plain"
}.unsafeCast<IHeaders>()
This is basically just using
js("{}")
to source a raw empty object and
dynamic
to assign it arbitrary properties: https://github.com/JetBrains/kotlin-wrappers/blob/master/kotlin-extensions/src/main/kotlin/kotlinext/js/Helpers.kt
I’ve not really tried dukat - only the one time, and it produced output that wouldn’t compile or wasn’t useful.
v
Hm, what I had tried right now was
Copy code
val response = HttpClient().post(
        requestUrl = "<http://localhost:9999/api/GetFiles>",
        data = "type=ProductId&url=$productId",
        additionalHeaders = js("{ 'Content-Type': 'application/x-www-form-urlencoded' }") as IHeaders
).await()
But that didn't work either, because the compiler removed the single quotes around
Content-Type
and then of course JS complains about the dash: But that actually sounds like a Kotlin compiler bug
a
It looks like you could use that generated interface like this:
jsObject<IHeaders> { this["Content-Type"] = "text/plain" }
I think it’s defining get/set property (from the Kotlin point of view) to just be passed through to the underlying JS
😷 1
😀 1
👍 1
v
Yeah, I'll try, thanks. Still hoped there would be a cleaner / type-safer way, like using a mapOf somehow 😄
👍 1
a
I guess supplementing Dukat’s output with a
fun Map<String,String>.toHeaders(): IHeaders
would make sense
v
Hm, no final release of
kotlin-extensions
, only pre-releases 😞
Yes, this did it, thanks
Copy code
fun Map<String, Any>.asIHeaders() = jsObject<IHeaders> {
    for ((name, value) in this@asIHeaders) {
        this[name] = value
    }
}
Copy code
val response = HttpClient().post(
        requestUrl = "<http://localhost:9999/api/GetFiles>",
        data = "type=ProductId&url=$productId",
        additionalHeaders = mapOf("Content-Type" to "application/x-www-form-urlencoded").asIHeaders()
).await()
Perfect, now it works, tysm
g
Thanks for the this[], solve my problem after 4 hours. Not sure about asIHeaders, not sure what that means off the top of my head, but I think we had the same issue. Really I think Kotlin Compiler should just keep the tick marks when it sees them and all is well. Search is a powerful tool in this, thanks guys. Let me know if you see any other obvious improvements:
Copy code
pluginsOpts = jsObject<dynamic> {
    this["grapesjs-lory-slider"] = jsObject<dynamic> {
        sliderBlock = jsObject<dynamic> {
            category = "Extra"
        }
    }
}