Как установить статическое свойство для класса в Kotlin для Javascript

У меня есть ситуация, когда мне нужно определить статическое свойство для класса в Kotlin, и когда оно скомпилировано в Javascript, оно становится истинным статическим полем для этого класса. В этой ситуации сопутствующие объекты не работают.

Например, если у меня есть абстрактный класс и его реализующий класс, как показано ниже:

abstract class MyAbstractClass{
  abstract val id: Int
}

class MyClass: MyAbstractClass(){
  override val id: Int = 1 //I want this to actually be "static" on the MyClass
}

Javascript, к которому это компилируется, таков:

function MyAbstractClass() {
}

function MyClass() {
  MyAbstractClass.call(this);
  this.id_jz5fma$_0 = 1;
}

Object.defineProperty(MyClass.prototype, 'id', {
  get: function () {
    return this.id_jz5fma$_0;
  }
});

Но то, что мне нужно, чтобы скомпилировать это:

function MyAbstractClass() {
}

function MyClass() {
  MyAbstractClass.call(this);
}

MyClass.id = 1;

Таким образом id поле на самом деле статически существует на MyClass без необходимости делать новый экземпляр MyClass,

Я пытался использовать объект-компаньон, но это создает отдельный объект / функцию под названием MyClass$Companion а затем назначает id поле к этому и никогда не назначает его статически MyClass,

Как я могу установить истинные статические поля, подобные этому, в Kotlin?

1 ответ

Решение

Прямо сейчас у нас нет прямого способа сделать это, поэтому я создал проблему https://youtrack.jetbrains.com/issue/KT-18891

В качестве обходного пути вы можете написать такую ​​функцию:

inline fun <reified T : Any> addStaticMembersTo(source: Any) {
    val c = T::class.js.asDynamic()
    val ownNames = js("Object").getOwnPropertyNames(source) as Array<String>
    val protoNames = js("Object").getOwnPropertyNames(source.asDynamic().constructor.prototype) as Array<String>

    for (name in ownNames + protoNames) {
        c[name] = source.asDynamic()[name]
    }
}

И используйте как:

class A {
    companion object {
        init {
            addStaticMembersTo<A>(object {
                val bar = 1
                fun foo() {}                
            })
        }
    }
}

или даже сделать члены объекта-компаньона доступными как статический член класса:

class B {
    companion object {
        val bar = 1
        fun foo() {}                

        // should be at the end of companion object
        init {
            addStaticMembersTo<B>(this)
        }
    }
}

Полный пример доступен здесь: https://try.kotl.in/#/UserProjects/uube1qikg3vsegtnefo0ad0jag/30f1qf87dt5k5vjhciirt4t108

Другие вопросы по тегам