https://kotlinlang.org logo
#javascript
Title
# javascript
s

Seth Madison

03/19/2024, 4:36 AM
Has anybody already written codegen to create overloads that accept an
external interface
of the args to allow for js-style object arguments? I’m imagining:
Copy code
@JsConstructor
@JsExport
data class ImportantData(foo: String, bar: Int)
Would end up generating JS-only code like:
Copy code
external interface ImportantDataArgs {
  val foo: String
  val bar: Int
}

inline fun createImportantData(args: ImportantDataArgs): ImportantData {
  return ImportantData(foo = args.foo, bar = args.bar)
}
That would ultimately generate a JS function that would be typed so that you could do:
Copy code
createImportantData({
  foo: "hello",
  bar: 123
});
Does something like this already exist?
e

Edoardo Luppi

03/19/2024, 8:43 AM
In don't think so, but I'm also thinking "why?" looking at the example. Maybe I'm not getting the full picture. Btw, you'd need
jso { ... }
for that last snippet to work.
a

Artem Kobzar

03/19/2024, 8:44 AM
I'm not quite sure that it's what you need, but I created a plugin for JS called
js-plain-objects
: https://github.com/JetBrains/kotlin/tree/master/plugins/js-plain-objects So, your code will look like:
Copy code
@JsPlainObject
external interface ImportantDataArgs {
  val foo: String
  val bar: Int
}

fun main() {
  val args = ImportantDataArgs(foo = "hello", bar = 123) // just a regular js object
  println(JSON.stringify(args)) // { foo: "hello", bar: 123 }
}
Unfortunately, it works only with K2.
e

Edoardo Luppi

03/19/2024, 8:49 AM
I think the goal here is being able to write plain objects exactly like JS. So for example
Copy code
const x = { 
  one: 1,
  two: 2,
}
You can do it with the external interface and the
jso
helper function
Copy code
val x = jso<ImportantDataArgs> { 
  one = 1
  two = 2
}
Although, I find this not idiomatic to Kotlin, and I'd prefer the plain object solution that is implemented for K2.
Btw, I was told K/JS IDE support for K2 will land in 2024.2
a

Artem Kobzar

03/19/2024, 8:57 AM
But, this is what the
@JsPlainObject
does. It compiles to exact JS object:
Copy code
// Kotlin
val args = ImportantDataArgs(foo = "hello", bar = 123)

// JavaScript
var args = { foo: "hello", bar: 123 }
✔️ 1
c

CLOVIS

03/19/2024, 10:26 AM
Can't you already write this?
Copy code
createImportantData(jso {
  foo = "hello"
  bar = 123
});
Sure, it's not exactly the same syntax, but it's fine, no?
Maybe the collections literal KEEP could help with this.
e

Edoardo Luppi

03/19/2024, 10:49 AM
Didn't even know there was a KEEP issue for that, or is it TBD?
c

CLOVIS

03/19/2024, 10:49 AM
I believe there is one and I remember reading it somewhat recently? But I can't find it at the moment 😅
s

Seth Madison

03/19/2024, 11:45 AM
Ah, sorry it wasn’t clear from my post. The last snippet is meant to be javascript code that consumers of my library could write. The goal is for consumers of my library, to be able to call functions and/or create objects with named arguments. The idiomatic way to do that in JS, is by passing an object as a single argument. So I want folks to be able to write JS (not Kotlin) like this:
Copy code
const important = createImportantData({
  foo: "hello",
  bar: 123
});
Instead of what they have to do today which is:
Copy code
const important = new ImportantData("hello", 123)
Does that make more sense?
c

CLOVIS

03/19/2024, 12:13 PM
Ah, I see. However, I do believe this already works for simple objects? Plain JS objects are really not great though, e.g. they don't carry inheritance information, so the result won't really be an instance of the class.
s

Seth Madison

03/19/2024, 4:41 PM
Yeah, it would just be so nice if I could provide that as a convenience for all constructors and functions. I may take a stab at a plugin when I get some time.
e

Edoardo Luppi

03/19/2024, 4:45 PM
My opinion is you'll complicate your life. For a couple of spots it might be ok tho
s

Seth Madison

04/14/2024, 3:33 AM
Cool! Now all we need is the codegen to create that for args based on an annotation!