diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelToTsDeclarations.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelToTsDeclarations.kt index d63d9f2356f..3ed27f8af80 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelToTsDeclarations.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/export/ExportModelToTsDeclarations.kt @@ -8,10 +8,7 @@ package org.jetbrains.kotlin.ir.backend.js.export import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin import org.jetbrains.kotlin.ir.backend.js.lower.isEs6PrimaryConstructorReplacement -import org.jetbrains.kotlin.ir.backend.js.utils.JsAnnotations -import org.jetbrains.kotlin.ir.backend.js.utils.getFqNameWithJsNameWhenAvailable -import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName -import org.jetbrains.kotlin.ir.backend.js.utils.sanitizeName +import org.jetbrains.kotlin.ir.backend.js.utils.* import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.util.* @@ -323,7 +320,13 @@ class ExportModelToTsDeclarations { val realNestedClasses = nonInnerClasses + innerClasses.map { it.withProtectedConstructors() } val tsIgnoreForPrivateConstructorInheritance = if (hasSuperClassWithPrivateConstructor()) { tsIgnore("extends class with private primary constructor") + "\n$indent" - } else "" + } else null + + val tsIgnoreForCompanionInheritance = if (hasSuperClassAndCompanion()) { + tsIgnore("https://github.com/microsoft/TypeScript/issues/4628") + "\n$indent" + } else null + + val tsIgnore = tsIgnoreForPrivateConstructorInheritance ?: tsIgnoreForCompanionInheritance ?: "" val klassExport = "$prefix$modifiers$keyword $name$renderedTypeParameters$superClassClause$superInterfacesClause {\n$bodyString}" @@ -338,7 +341,7 @@ class ExportModelToTsDeclarations { ) } else "" - return if (name.isValidES5Identifier()) tsIgnoreForPrivateConstructorInheritance + klassExport + staticsExport + interfaceCompanionsString else "" + return if (name.isValidES5Identifier()) tsIgnore + klassExport + staticsExport + interfaceCompanionsString else "" } private fun ExportedRegularClass.hasSuperClassWithPrivateConstructor(): Boolean { @@ -347,6 +350,11 @@ class ExportModelToTsDeclarations { return exportedConstructor?.let { it.visibility == DescriptorVisibilities.PRIVATE || it.hasAnnotation(JsAnnotations.jsExportIgnoreFqn) } ?: true } + private fun ExportedRegularClass.hasSuperClassAndCompanion(): Boolean { + val superClass = superClasses.firstIsInstanceOrNull()?.ir?.takeIf { !it.isObject } + return superClass != null && ir.companionObject()?.isJsExportIgnore() == false + } + private fun List.toExtendsClause(indent: String): String { if (isEmpty()) return "" diff --git a/js/js.translator/testData/typescript-export/objects-in-exported-file/objects.d.ts b/js/js.translator/testData/typescript-export/objects-in-exported-file/objects.d.ts index 53702d022c4..cdfba734d8c 100644 --- a/js/js.translator/testData/typescript-export/objects-in-exported-file/objects.d.ts +++ b/js/js.translator/testData/typescript-export/objects-in-exported-file/objects.d.ts @@ -41,6 +41,18 @@ declare namespace JS_TESTS { function createNested1(): typeof foo.Parent.Nested1; function createNested2(): foo.Parent.Nested1.Nested2; function createNested3(): foo.Parent.Nested1.Nested2.Companion.Nested3; + abstract class BaseWithCompanion { + constructor(); + static get Companion(): { + get any(): string; + }; + } + /* @ts-ignore: https://github.com/microsoft/TypeScript/issues/4628 */ + class ChildWithCompanion extends foo.BaseWithCompanion { + constructor(); + static get Companion(): { + }; + } } namespace _objects_ { const foo$Parent$Nested1: { diff --git a/js/js.translator/testData/typescript-export/objects-in-exported-file/objects.kt b/js/js.translator/testData/typescript-export/objects-in-exported-file/objects.kt index 1953bbc1b18..6442df3f07c 100644 --- a/js/js.translator/testData/typescript-export/objects-in-exported-file/objects.kt +++ b/js/js.translator/testData/typescript-export/objects-in-exported-file/objects.kt @@ -63,4 +63,15 @@ fun createNested2(): Parent.Nested1.Nested2 { fun createNested3(): Parent.Nested1.Nested2.Companion.Nested3 { return Parent.Nested1.Nested2.Companion.Nested3() +} + + +abstract class BaseWithCompanion { + companion object { + val any: String = "ANYTHING" + } +} + +class ChildWithCompanion : BaseWithCompanion() { + companion object } \ No newline at end of file diff --git a/js/js.translator/testData/typescript-export/objects-in-exported-file/objects__main.ts b/js/js.translator/testData/typescript-export/objects-in-exported-file/objects__main.ts index 347735a0de5..9a70c9ce1fa 100644 --- a/js/js.translator/testData/typescript-export/objects-in-exported-file/objects__main.ts +++ b/js/js.translator/testData/typescript-export/objects-in-exported-file/objects__main.ts @@ -7,6 +7,8 @@ import createNested1 = JS_TESTS.foo.createNested1; import createNested2 = JS_TESTS.foo.createNested2; import createNested3 = JS_TESTS.foo.createNested3; import WithSimpleObjectInside = JS_TESTS.foo.WithSimpleObjectInside; +import BaseWithCompanion = JS_TESTS.foo.BaseWithCompanion; +import ChildWithCompanion = JS_TESTS.foo.ChildWithCompanion; function assert(condition: boolean) { if (!condition) { @@ -34,5 +36,6 @@ function box(): string { assert(WithSimpleObjectInside.value === "WithSimpleObjectInside"); assert(WithSimpleObjectInside.SimpleObject.value === "SimpleObject"); + return "OK"; } \ No newline at end of file diff --git a/js/js.translator/testData/typescript-export/objects/objects.d.ts b/js/js.translator/testData/typescript-export/objects/objects.d.ts index 53702d022c4..cdfba734d8c 100644 --- a/js/js.translator/testData/typescript-export/objects/objects.d.ts +++ b/js/js.translator/testData/typescript-export/objects/objects.d.ts @@ -41,6 +41,18 @@ declare namespace JS_TESTS { function createNested1(): typeof foo.Parent.Nested1; function createNested2(): foo.Parent.Nested1.Nested2; function createNested3(): foo.Parent.Nested1.Nested2.Companion.Nested3; + abstract class BaseWithCompanion { + constructor(); + static get Companion(): { + get any(): string; + }; + } + /* @ts-ignore: https://github.com/microsoft/TypeScript/issues/4628 */ + class ChildWithCompanion extends foo.BaseWithCompanion { + constructor(); + static get Companion(): { + }; + } } namespace _objects_ { const foo$Parent$Nested1: { diff --git a/js/js.translator/testData/typescript-export/objects/objects.kt b/js/js.translator/testData/typescript-export/objects/objects.kt index cc804d74080..7f184587b15 100644 --- a/js/js.translator/testData/typescript-export/objects/objects.kt +++ b/js/js.translator/testData/typescript-export/objects/objects.kt @@ -59,4 +59,15 @@ fun createNested2(): Parent.Nested1.Nested2 { @JsExport fun createNested3(): Parent.Nested1.Nested2.Companion.Nested3 { return Parent.Nested1.Nested2.Companion.Nested3() +} + +@JsExport +abstract class BaseWithCompanion { + companion object { + val any: String = "ANYTHING" + } +} +@JsExport +class ChildWithCompanion : BaseWithCompanion() { + companion object } \ No newline at end of file