4.1 KiB
Interop with native JavaScript
Goal
Provide the ways to interact with native JavaScript.
Type-safe Declarations
Annotation native
TODO
Annotation nativeInvoke
Calls to functions annotated by nativeInvoke will be translated to calls of receiver with the arguments provided for original call.
Applicable to:
- member functions of native declarations
- non-member extension functions
Example:
native
class A {
nativeInvoke
fun invoke(): String = noImpl
nativeInvoke
fun foo(a: Int): Int = noImpl
}
fun A.bar(a: String): Int = noImpl
fun test(baz: A) {
baz()
baz.invoke()
baz.foo(1)
baz.bar("str")
}
Function test will be translated to:
...
test: function (baz) {
foo()
foo()
foo(1)
foo("str")
}
...
Annotation nativeGetter
Calls to functions annotated by nativeGetter will be translated to square/index operation on the receiver with the argument provided for original call.
Applicable to:
- member functions of native declarations
- non-member extension functions
Requirements:
- must have exactly one argument
- type of the argument must be
Stringor subtype ofNumber - default values are prohibited
- return type must be nullable
Example:
native
class A {
nativeGetter
fun get(a: String): String? = noImpl
nativeGetter
fun foo(a: Int): Int? = noImpl
}
class B
nativeGetter
fun B.get(a: String): Int? = noImpl
nativeGetter
fun B.bar(a: Int): Int? = noImpl
fun test(a: A, b: B) {
a["foo"]
a.get("bar")
a.foo(1)
b["foo"]
b.get("bar")
b.bar(1)
}
Function test will be translated to:
...
test: function (a, b) {
a["foo"]
a["bar"]
a[1]
b["foo"]
b["bar"]
b[1]
}
...
Annotation nativeSetter
Calls of functions annotated by nativeSetter will be translated to assignment of the second argument to the receiver
indexed (with square/index operation) with the first argument.
Applicable to:
- member functions of native declarations
- non-member extension functions
Requirements:
- must have exactly two arguments
- type of the first argument must be
Stringor subtype ofNumber - default values are prohibited
- the return type is either
Unitor a supertype of the second parameter's type
Example:
native
class A {
nativeSetter
fun set(a: String, v: Any) {}
nativeSetter
fun foo(a: Int, v: A) {}
}
class B
nativeSetter
fun B.set(a: String, v: B) {}
nativeSetter
fun B.bar(a: String, v: B?) {}
fun test(a: A, b: B) {
a["foo"] = "text"
a.set("bar", "value")
a.foo(1, A())
b["foo"] = B()
b.set("bar", b)
b.bar("a", null)
}
Function test will be translated to:
...
test: function (a, b) {
a["foo"] = "text"
a["bar"] = "value"
a[1] = A()
b["foo"] = B()
b["bar"] = b
b["a"] = null
}
...
Function js
Argument of js function is parsed as JavaScript code and injected directly into the JavaScript code generated by the compiler.
Requirements:
- the argument should be a compile time constant of type
String
Example:
fun test1() {
js("console.log('Hello')")
}
fun test2(a: String) = js("""
var r = foo(a);
return r;
""")
is translated to:
function test1() {
console.log('Hello')
}
function test2(a) {
var r = foo(a);
return r;
}
Dynamic types
All dynamic calls with explicit names (regular and infix function calls, and property calls) are translated "as is", without mangling.
Additionally, many operations when applied to a receiver of type dynamic are translated "as is", instead of by convention.
Operations translated "as is" to JavaScript:
- binary:
+,-,*,/,%,>,<>=,<=,==,!=,===,!==,&&,|| - unary
- prefix:
-,+,! - prefix and postfix:
++,-- - assignments:
+=,-=,*=,/=,%= - indexed access:
- read:
d[a], more than one argument is an error - write:
d[a1] = a2, more than one argument in[]is an error inand!inare forbidden, an error is reported
Note:
..is translated to a call torangeTo~,|,&and^are not supported (there's no Kotlin code that translates to these operations)