Migrating Kotlin/JS projects to the IR compiler
We replaced the old Kotlin/JS compiler with the IR-based compiler in order to unify Kotlin's behavior on all platforms and to make it possible to implement new JS-specific optimizations, among other reasons. You can learn more about the internal differences between the two compilers in the blog post Migrating our Kotlin/JS app to the new IR compiler by Sebastian Aigner.
Due to the significant differences between the compilers, switching your Kotlin/JS project from the old backend to the new one may require adjusting your code. On this page, we've compiled a list of known migration issues along with suggested solutions.
Note that this guide may change over time as we fix issues and find new ones. Please help us keep it complete – report any issues you encounter when switching to the IR compiler by submitting them to our issue tracker YouTrack or filling out this form.
Convert JS- and React-related classes and interfaces to external interfaces
Issue: Using Kotlin interfaces and classes (including data classes) that derive from pure JS classes, such as React's State
and Props
, can cause a ClassCastException
. Such exceptions appear because the compiler attempts to work with instances of these classes as if they were Kotlin objects, when they actually come from JS.
Solution: convert all classes and interfaces that derive from pure JS classes to external interfaces:
In IntelliJ IDEA, you can use these structural search and replace templates to automatically mark interfaces as external
:
Convert properties of external interfaces to var
Issue: properties of external interfaces in Kotlin/JS code can't be read-only (val
) properties because their values can be assigned only after the object is created with js()
or jso()
(a helper function from kotlin-wrappers
):
Solution: convert all properties of external interfaces to var
:
Convert functions with receivers in external interfaces to regular functions
Issue: external declarations can't contain functions with receivers, such as extension functions or properties with corresponding functional types.
Solution: convert such functions and properties to regular functions by adding the receiver object as an argument:
Create plain JS objects for interoperability
Issue: properties of a Kotlin object that implements an external interface are not enumerable. This means that they are not visible for operations that iterate over the object's properties, for example:
for (var name in obj)
console.log(obj)
JSON.stringify(obj)
Although they are still accessible by the name: obj.myProperty
Solution 1: create plain JavaScript objects with js()
or jso()
(a helper function from kotlin-wrappers
):
Solution 2: create objects with kotlin.js.json()
:
Replace toString() calls on function references with .name
Issue: in the IR backend, calling toString()
on function references doesn't produce unique values.
Solution: use the name
property instead of toString()
.
Explicitly specify binaries.executable() in the build script
Issue: the compiler doesn't produce executable .js
files.
This may happen because the default compiler produces JavaScript executables by default while the IR compiler needs an explicit instruction to do this. Learn more in the Kotlin/JS project setup instruction.
Solution: add the line binaries.executable()
to the project's build.gradle(.kts)
.
Additional troubleshooting tips when working with the Kotlin/JS IR compiler
These hints may help you when troubleshooting problems in your projects using the Kotlin/JS IR compiler.
Make boolean properties nullable in external interfaces
Issue: when you call toString
on a Boolean
from an external interface, you're getting an error like Uncaught TypeError: Cannot read properties of undefined (reading 'toString')
. JavaScript treats the null
or undefined
values of a boolean variable as false
. If you rely on calling toString
on a Boolean
that may be null
or undefined
(for example when your code is called from JavaScript code you have no control over), be aware of this:
Solution: you can make your Boolean
properties of external interfaces nullable (Boolean?
):