feat(@JsExport for interfaces): add ability to export interfaces in TypeScript.

This commit is contained in:
Artem Kobzar
2021-11-18 10:07:38 +00:00
committed by Space
parent 4dcfd38236
commit d5dd35cb20
35 changed files with 366 additions and 55 deletions
@@ -106,7 +106,7 @@ sealed class ExportedType {
val returnType: ExportedType
) : ExportedType()
class ClassType(val name: String, val arguments: List<ExportedType>) : ExportedType()
class ClassType(val name: String, val arguments: List<ExportedType>, val ir: IrClass) : ExportedType()
class TypeParameter(val name: String) : ExportedType()
class Nullable(val baseType: ExportedType) : ExportedType()
class ErrorType(val comment: String) : ExportedType()
@@ -483,7 +483,8 @@ class ExportModelGenerator(
ClassKind.ENUM_CLASS,
ClassKind.INTERFACE -> ExportedType.ClassType(
name,
type.arguments.map { exportTypeArgument(it) }
type.arguments.map { exportTypeArgument(it) },
klass
)
}.withImplicitlyExported(isImplicitlyExported)
}
@@ -19,7 +19,15 @@ fun ExportedModule.toTypeScript(): String {
}
fun wrapTypeScript(name: String, moduleKind: ModuleKind, dts: String): String {
val types = "${moduleKind.indent}type Nullable<T> = T | null | undefined\n"
val declareKeyword = when (moduleKind) {
ModuleKind.PLAIN -> ""
else -> "declare "
}
val types = """
type Nullable<T> = T | null | undefined
${declareKeyword}const __doNotImplementIt: unique symbol
type __doNotImplementIt = typeof __doNotImplementIt
""".trimIndent().prependIndent(moduleKind.indent) + "\n"
val declarationsDts = types + dts
@@ -117,14 +125,16 @@ fun ExportedDeclaration.toTypeScript(indent: String, prefix: String = ""): Strin
val superClassClause = superClass?.let { it.toExtendsClause(indent) } ?: ""
val superInterfacesClause = superInterfaces.toImplementsClause(superInterfacesKeyword, indent)
val members = members.map {
if (!ir.isInner || it !is ExportedFunction || !it.isStatic) {
it
} else {
// Remove $outer argument from secondary constructors of inner classes
it.copy(parameters = it.parameters.drop(1))
val members = members
.let { if (shouldNotBeImplemented()) it.withMagicProperty() else it }
.map {
if (!ir.isInner || it !is ExportedFunction || !it.isStatic) {
it
} else {
// Remove $outer argument from secondary constructors of inner classes
it.copy(parameters = it.parameters.drop(1))
}
}
}
val (innerClasses, nonInnerClasses) = nestedClasses.partition { it.ir.isInner }
val innerClassesProperties = innerClasses.map { it.toReadonlyProperty() }
@@ -179,6 +189,26 @@ fun List<ExportedType>.toImplementsClause(superInterfacesKeyword: String, indent
}
}
fun ExportedClass.shouldNotBeImplemented(): Boolean {
return (isInterface && !ir.isExternal) || superInterfaces.any { it is ExportedType.ClassType && !it.ir.isExternal }
}
fun List<ExportedDeclaration>.withMagicProperty(): List<ExportedDeclaration> {
return plus(
ExportedProperty(
"__doNotUseIt",
ExportedType.TypeParameter("__doNotImplementIt"),
mutable = false,
isMember = true,
isStatic = false,
isAbstract = false,
isProtected = false,
irGetter = null,
irSetter = null
)
)
}
fun IrClass.asNestedClassAccess(): String {
val name = getJsNameOrKotlinName().identifier
if (parent !is IrClass) return name
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.backend.js.export.isEnumFakeOverriddenDeclaration
import org.jetbrains.kotlin.ir.backend.js.export.isExported
@@ -125,24 +126,21 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
)
}
fun IrSimpleFunction.accessorRef(): JsNameRef? =
when (visibility) {
DescriptorVisibilities.PRIVATE -> null
else -> JsNameRef(
context.getNameForMemberFunction(this),
classPrototypeRef
)
}
val overriddenSymbols = property.getter?.overriddenSymbols.orEmpty()
// Don't generate `defineProperty` if the property overrides a property from an exported class,
// because we've already generated `defineProperty` for the base class property.
// In other words, we only want to generate `defineProperty` once for each property.
// The exception is case when we override val with var,
// so we need regenerate `defineProperty` with setter.
val noOverriddenGetter = property.getter?.overriddenSymbols?.isEmpty() == true
// P.S. If the overridden property is owned by an interface - we should generate defineProperty
// for overridden property in the first class which override those properties
val hasOverriddenExportedInterfaceProperties = overriddenSymbols.any { it.owner.parentClassOrNull.isExportedInterface() }
&& !overriddenSymbols.any { it.owner.parentClassOrNull.isExportedClass() }
val overriddenExportedGetter = (property.getter?.overriddenSymbols?.isNotEmpty() == true &&
property.getter?.isOverriddenExported(context.staticContext.backendContext) == true)
val getterOverridesExternal = property.getter?.overridesExternal() == true
val overriddenExportedGetter = !property.getter?.overriddenSymbols.isNullOrEmpty() &&
property.getter?.isOverriddenExported(context.staticContext.backendContext) == true
val noOverriddenExportedSetter = property.setter?.isOverriddenExported(context.staticContext.backendContext) == false
@@ -150,8 +148,9 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
property.isEnumFakeOverriddenDeclaration(context.staticContext.backendContext)
if (irClass.isExported(context.staticContext.backendContext) &&
(noOverriddenGetter || needsOverride) ||
property.getter?.overridesExternal() == true ||
(overriddenSymbols.isEmpty() || needsOverride) ||
hasOverriddenExportedInterfaceProperties ||
getterOverridesExternal ||
property.getJsName() != null
) {
@@ -168,31 +167,24 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
// set: Foo.prototype._set_prop__a4enbm_k$
// });
val getterForwarder = if (property.getter?.modality == Modality.FINAL) property.getter?.accessorRef()
else {
property.getter?.propertyAccessorForwarder("getter forwarder") { getterRef ->
JsReturn(
JsInvocation(
getterRef
)
)
val getterForwarder = property.getter
.takeIf { it.shouldExportAccessor() }
.getOrGenerateIfFinal {
propertyAccessorForwarder("getter forwarder") {
JsReturn(JsInvocation(it))
}
}
}
val setterForwarder = if (property.setter?.modality == Modality.FINAL) property.setter?.accessorRef()
else {
property.setter?.let {
val setterForwarder = property.setter
.takeIf { it.shouldExportAccessor() }
.getOrGenerateIfFinal {
val setterArgName = JsName("value", false)
it.propertyAccessorForwarder("setter forwarder") { setterRef ->
JsInvocation(
setterRef,
JsNameRef(setterArgName)
).makeStmt()
propertyAccessorForwarder("setter forwarder") {
JsInvocation(it, JsNameRef(setterArgName)).makeStmt()
}?.apply {
parameters.add(JsParameter(setterArgName))
}
}
}
classBlock.statements += JsExpressionStatement(
defineProperty(
@@ -209,6 +201,34 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
return classBlock
}
private inline fun IrSimpleFunction?.getOrGenerateIfFinal(generateFunc: IrSimpleFunction.() -> JsFunction?): JsExpression? {
if (this == null) return null
return if (modality == Modality.FINAL) accessorRef() else generateFunc()
}
private fun IrSimpleFunction?.shouldExportAccessor(): Boolean {
if (this == null) return false
if (parentAsClass.isExported(context.staticContext.backendContext)) return true
val property = correspondingPropertySymbol!!.owner
if (property.isOverriddenExported(context.staticContext.backendContext)) {
return isOverriddenExported(context.staticContext.backendContext)
}
return overridesExternal() || property.getJsName() != null
}
private fun IrSimpleFunction.accessorRef(): JsNameRef? =
when (visibility) {
DescriptorVisibilities.PRIVATE -> null
else -> JsNameRef(
context.getNameForMemberFunction(this),
classPrototypeRef
)
}
private fun IrSimpleFunction.generateAssignmentIfMangled(memberRef: JsExpression) {
if (
irClass.isExported(context.staticContext.backendContext) &&
@@ -143,11 +143,14 @@ fun translateCall(
val jsExtensionReceiver = expression.extensionReceiver?.accept(transformer, context)
val arguments = translateCallArguments(expression, context, transformer)
// Transform external property accessor call
// @JsName-annotated external property accessors are translated as function calls
// Transform external and interface's property accessor call
// @JsName-annotated external and interface's property accessors are translated as function calls
if (function.getJsName() == null) {
val property = function.correspondingPropertySymbol?.owner
if (property != null && property.isEffectivelyExternal()) {
if (
property != null &&
(property.isEffectivelyExternal() || property.isExportedInterfaceMember())
) {
val propertyName = context.getNameForProperty(property)
val nameRef = when (jsDispatchReceiver) {
null -> jsGlobalVarRef(JsNameRef(propertyName))
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.ir.backend.js.utils
import org.jetbrains.kotlin.descriptors.isInterface
import org.jetbrains.kotlin.descriptors.isClass
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.util.parentClassOrNull
fun IrDeclaration?.isExportedClass() =
this is IrClass && kind.isClass && isJsExport()
fun IrDeclaration?.isExportedInterface() =
this is IrClass && kind.isInterface && isJsExport()
fun IrDeclaration.isExportedInterfaceMember() =
parentClassOrNull.isExportedInterface()
@@ -20,7 +20,7 @@ open class ExportedGenericClass<T>
class <!NON_EXPORTABLE_TYPE("super; ExportedGenericClass<NonExportedClass>")!>ExportedClass3<!> : ExportedGenericClass<NonExportedClass>()
@JsExport
interface <!WRONG_EXPORTED_DECLARATION!>ExportedGenericInterface<!><T>
interface ExportedGenericInterface<T>
@JsExport
class <!NON_EXPORTABLE_TYPE("super; ExportedGenericInterface<NonExportedClass>")!>ExportedClass4<!> : ExportedGenericInterface<NonExportedClass>
@@ -14,4 +14,4 @@ fun <<!NON_EXPORTABLE_TYPE("upper bound; C")!>T : C<!>>foo() { }
class A<<!NON_EXPORTABLE_TYPE("upper bound; C")!>T : C<!>, <!NON_EXPORTABLE_TYPE("upper bound; I")!>S: I<!>>
@JsExport
interface <!WRONG_EXPORTED_DECLARATION!>I2<!><<!NON_EXPORTABLE_TYPE("upper bound; C"), NON_EXPORTABLE_TYPE("upper bound; I")!>T<!>> where T : C, T : I
interface I2<<!NON_EXPORTABLE_TYPE("upper bound; C"), NON_EXPORTABLE_TYPE("upper bound; I")!>T<!>> where T : C, T : I
@@ -18,11 +18,23 @@ val String.extensionProperty<!>
annotation class <!WRONG_EXPORTED_DECLARATION("annotation class")!>AnnotationClass<!>
@JsExport
interface <!WRONG_EXPORTED_DECLARATION("interface")!>SomeInterface<!>
interface SomeInterface
@JsExport
external interface GoodInterface
@JsExport
interface InterfaceWithCompanion {
companion <!WRONG_EXPORTED_DECLARATION("companion object inside exported interface")!>object<!> {
fun foo() = 42
}
}
@JsExport
interface OuterInterface {
class <!WRONG_EXPORTED_DECLARATION("nested class inside exported interface")!>Nested<!>
}
@JsExport
value class <!WRONG_EXPORTED_DECLARATION("value class")!>A(val a: Int)<!>
@@ -50,6 +50,33 @@ package foo {
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@kotlin.js.JsExport public interface InterfaceWithCompanion {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public companion object Companion {
private constructor Companion()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
@kotlin.js.JsExport public interface OuterInterface {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public final class Nested {
public constructor Nested()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
@kotlin.js.JsExport public interface SomeInterface {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
@@ -32,3 +32,6 @@ inline val ClassKind.isInterface: Boolean
inline val ClassKind.isEnumClass: Boolean
get() = this == ClassKind.ENUM_CLASS
inline val ClassKind.isClass: Boolean
get() = this == ClassKind.CLASS
@@ -136,6 +136,11 @@ val DeclarationDescriptor.isInsidePrivateClass: Boolean
return parent != null && DescriptorVisibilities.isPrivate(parent.visibility)
}
val DeclarationDescriptor.isInsideInterface: Boolean
get() {
val parent = containingDeclaration as? ClassDescriptor
return parent != null && parent.kind.isInterface
}
fun ClassDescriptor.getSuperClassNotAny(): ClassDescriptor? {
for (supertype in defaultType.constructor.supertypes) {
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
import org.jetbrains.kotlin.resolve.descriptorUtil.isEffectivelyExternal
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty
import org.jetbrains.kotlin.resolve.descriptorUtil.isInsideInterface
import org.jetbrains.kotlin.resolve.inline.isInlineWithReified
import org.jetbrains.kotlin.resolve.isInlineClass
import org.jetbrains.kotlin.types.KotlinType
@@ -109,12 +110,15 @@ object JsExportDeclarationChecker : DeclarationChecker {
}
val wrongDeclaration: String? = when (descriptor.kind) {
INTERFACE -> if (descriptor.isExternal) null else "interface"
ANNOTATION_CLASS -> "annotation class"
CLASS -> if (descriptor.isInlineClass()) {
"${if (descriptor.isInline) "inline " else ""}${if (descriptor.isValue) "value " else ""}class"
CLASS -> when {
descriptor.isInsideInterface -> "nested class inside exported interface"
descriptor.isInlineClass() -> "${if (descriptor.isInline) "inline " else ""}${if (descriptor.isValue) "value " else ""}class"
else -> null
}
else -> if (descriptor.isInsideInterface) {
"${if (descriptor.isCompanionObject) "companion object" else "nested/inner declaration"} inside exported interface"
} else null
else -> null
}
if (wrongDeclaration != null) {
@@ -2070,6 +2070,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
runTest("js/js.translator/testData/box/export/exportEnumClass.kt");
}
@Test
@TestMetadata("exportInterface.kt")
public void testExportInterface() throws Exception {
runTest("js/js.translator/testData/box/export/exportInterface.kt");
}
@Test
@TestMetadata("exportNestedClass.kt")
public void testExportNestedClass() throws Exception {
@@ -2460,6 +2460,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
runTest("js/js.translator/testData/box/export/exportEnumClass.kt");
}
@Test
@TestMetadata("exportInterface.kt")
public void testExportInterface() throws Exception {
runTest("js/js.translator/testData/box/export/exportInterface.kt");
}
@Test
@TestMetadata("exportNestedClass.kt")
public void testExportNestedClass() throws Exception {
@@ -1,6 +1,7 @@
// EXPECTED_REACHABLE_NODES: 1288
// IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6
@JsExport
interface I {
val a: Char
}
+79
View File
@@ -0,0 +1,79 @@
// IGNORE_BACKEND: JS
// RUN_PLAIN_BOX_FUNCTION
// INFER_MAIN_MODULE
// MODULE: export_interface
// FILE: lib.kt
@JsExport
interface I {
val value: Int
var variable: Int
fun foo(): String
}
open class NotExportedClass(override var value: Int) : I {
override var variable: Int = value
override open fun foo(): String = "Not Exported"
}
@JsExport
class ExportedClass(override val value: Int) : I {
override var variable: Int = value
override fun foo(): String = "Exported"
}
@JsExport
class AnotherOne : NotExportedClass(42) {
override fun foo(): String = "Another One Exported"
}
@JsExport
fun generateNotExported(value: Int): NotExportedClass {
return NotExportedClass(value)
}
@JsExport
fun consume(i: I): String {
return "Value is ${i.value}, variable is ${i.variable} and result is '${i.foo()}'"
}
// FILE: test.js
function box() {
const { I, ExportedClass, AnotherOne, generateNotExported, consume } = this["export_interface"]
if (I !== undefined) return "Fail: module should not export interface in runtime"
const exported = new ExportedClass(1)
const another = new AnotherOne()
const notExported = generateNotExported (3)
if (exported.foo() !== "Exported") return "Fail: foo function was not generated for ExportedClass"
if (another.foo() !== "Another One Exported") return "Fail: foo function was not generated for AnotherOne"
if (notExported.foo() !== "Not Exported") return "Fail: foo function was not generated for NotExportedClass"
if (exported.value !== 1) return "Fail: value getter was not generated for ExportedClass"
if (another.value !== 42) return "Fail: value getter was not generated for AnotherOne"
if (notExported.value !== 3) return "Fail: value getter was not generated for NotExportedClass"
if (exported.variable !== 1) return "Fail: variable getter was not generated for ExportedClass"
if (another.variable !== 42) return "Fail: variable getter was not generated for AnotherOne"
if (notExported.variable !== 3) return "Fail: variable getter was not generated for NotExportedClass"
exported.variable = 101
another.variable = 102
notExported.variable = 103
if (exported.variable !== 101) return "Fail: variable setter was not generated for ExportedClass"
if (another.variable !== 102) return "Fail: variable setter was not generated for AnotherOne"
if (notExported.variable !== 103) return "Fail: variable setter was not generated for NotExportedClass"
notExported.value = 42
if (notExported.value !== 3) return "Fail: value setter was generated for NotExportedClass, but it shouldn't"
if (consume(exported) !== "Value is 1, variable is 101 and result is 'Exported'") return "Fail: methods or fields of ExportedClass was mangled"
if (consume(another) !== "Value is 42, variable is 102 and result is 'Another One Exported'") return "Fail: methods or fields of AnotherOne was mangled"
if (consume(notExported) !== "Value is 3, variable is 103 and result is 'Not Exported'") return "Fail: methods or fields of NotExported was mangled"
return "OK"
}
@@ -1,5 +1,7 @@
declare namespace JS_TESTS {
type Nullable<T> = T | null | undefined
const __doNotImplementIt: unique symbol
type __doNotImplementIt = typeof __doNotImplementIt
namespace foo {
class TestInner {
constructor(a: string);
@@ -1,5 +1,7 @@
declare namespace JS_TESTS {
type Nullable<T> = T | null | undefined
const __doNotImplementIt: unique symbol
type __doNotImplementIt = typeof __doNotImplementIt
class ClassWithDefaultCtor {
constructor();
readonly x: string;
@@ -1,5 +1,7 @@
declare namespace JS_TESTS {
type Nullable<T> = T | null | undefined
const __doNotImplementIt: unique symbol
type __doNotImplementIt = typeof __doNotImplementIt
namespace foo {
const _val: number;
let _var: number;
@@ -123,5 +125,17 @@ declare namespace JS_TESTS {
readonly prop: string;
}
}
interface TestInterface {
readonly value: string;
getOwnerName(): string;
readonly __doNotUseIt: __doNotImplementIt;
}
class TestInterfaceImpl implements foo.TestInterface {
constructor(value: string);
readonly value: string;
getOwnerName(): string;
readonly __doNotUseIt: __doNotImplementIt;
}
function processInterface(test: foo.TestInterface): string;
}
}
@@ -179,4 +179,21 @@ enum class TestEnumClass(val constructorParameter: String) {
class Nested {
val prop: String = "hello2"
}
}
@JsExport
interface TestInterface {
val value: String
fun getOwnerName(): String
}
@JsExport
class TestInterfaceImpl(override val value: String) : TestInterface {
override fun getOwnerName() = "TestInterfaceImpl"
}
@JsExport
fun processInterface(test: TestInterface): String {
return "Owner ${test.getOwnerName()} has value '${test.value}'"
}
@@ -27,6 +27,8 @@ var TestSealed = JS_TESTS.foo.TestSealed;
var TestAbstract = JS_TESTS.foo.TestAbstract;
var TestDataClass = JS_TESTS.foo.TestDataClass;
var TestEnumClass = JS_TESTS.foo.TestEnumClass;
var TestInterfaceImpl = JS_TESTS.foo.TestInterfaceImpl;
var processInterface = JS_TESTS.foo.processInterface;
function assert(condition) {
if (!condition) {
throw "Assertion failed";
@@ -112,5 +114,8 @@ function box() {
assert(TestEnumClass.A.ordinal === 0);
assert(TestEnumClass.B.ordinal === 1);
assert(new TestEnumClass.Nested().prop == "hello2");
assert(processInterface(new TestInterfaceImpl("bar")) == "Owner TestInterfaceImpl has value 'bar'");
// @ts-expect-error "Just test that this code will throw compilation error for a user"
assert(processInterface({ value: "bar", getOwnerName: function () { return "RandomObject"; } }) == "Owner RandomObject has value 'bar'");
return "OK";
}
@@ -27,6 +27,8 @@ import TestSealed = JS_TESTS.foo.TestSealed;
import TestAbstract = JS_TESTS.foo.TestAbstract;
import TestDataClass = JS_TESTS.foo.TestDataClass;
import TestEnumClass = JS_TESTS.foo.TestEnumClass;
import TestInterfaceImpl = JS_TESTS.foo.TestInterfaceImpl;
import processInterface = JS_TESTS.foo.processInterface;
function assert(condition: boolean) {
if (!condition) {
@@ -133,5 +135,10 @@ function box(): string {
assert(new TestEnumClass.Nested().prop == "hello2")
assert(processInterface(new TestInterfaceImpl("bar")) == "Owner TestInterfaceImpl has value 'bar'")
// @ts-expect-error "Just test that this code will throw compilation error for a user"
assert(processInterface({ value: "bar", getOwnerName: () => "RandomObject" }) == "Owner RandomObject has value 'bar'")
return "OK";
}
@@ -1,5 +1,7 @@
declare namespace JS_TESTS {
type Nullable<T> = T | null | undefined
const __doNotImplementIt: unique symbol
type __doNotImplementIt = typeof __doNotImplementIt
namespace foo {
@@ -1,6 +1,11 @@
declare namespace JS_TESTS {
type Nullable<T> = T | null | undefined
const __doNotImplementIt: unique symbol
type __doNotImplementIt = typeof __doNotImplementIt
namespace foo {
interface ExportedInterface {
readonly __doNotUseIt: __doNotImplementIt;
}
function producer(value: number): any/* foo.NonExportedType */;
function consumer(value: any/* foo.NonExportedType */): number;
class A {
@@ -14,5 +19,16 @@ declare namespace JS_TESTS {
class C /* implements foo.NonExportedInterface */ {
constructor();
}
class D implements foo.ExportedInterface/*, foo.NonExportedInterface */ {
constructor();
readonly __doNotUseIt: __doNotImplementIt;
}
class E /* extends foo.NonExportedType */ implements foo.ExportedInterface {
constructor();
readonly __doNotUseIt: __doNotImplementIt;
}
class F extends foo.A /* implements foo.NonExportedInterface */ {
constructor();
}
}
}
@@ -11,6 +11,9 @@ package foo
interface NonExportedInterface
open class NonExportedType(val value: Int)
@JsExport
interface ExportedInterface
@JsExport
fun producer(value: Int): NonExportedType {
return NonExportedType(value)
@@ -22,7 +25,7 @@ fun consumer(value: NonExportedType): Int {
}
@JsExport
class A(var value: NonExportedType) {
open class A(var value: NonExportedType) {
fun <T: NonExportedType> increment(t: T): NonExportedType {
return NonExportedType(value = t.value + 1)
}
@@ -32,4 +35,13 @@ class A(var value: NonExportedType) {
class B(v: Int) : NonExportedType(v)
@JsExport
class C : NonExportedInterface
class C : NonExportedInterface
@JsExport
class D : NonExportedInterface, ExportedInterface
@JsExport
class E : NonExportedType(42), ExportedInterface
@JsExport
class F : A(NonExportedType(42)), NonExportedInterface
@@ -1,5 +1,7 @@
declare namespace JS_TESTS {
type Nullable<T> = T | null | undefined
const __doNotImplementIt: unique symbol
type __doNotImplementIt = typeof __doNotImplementIt
namespace foo {
interface I<T, S, U> {
x: T;
@@ -26,12 +26,12 @@ var Impl = /** @class */ (function (_super) {
};
Object.defineProperty(Impl.prototype, "acAbstractProp", {
get: function () { return "Impl"; },
enumerable: true,
enumerable: false,
configurable: true
});
Object.defineProperty(Impl.prototype, "y", {
get: function () { return true; },
enumerable: true,
enumerable: false,
configurable: true
});
return Impl;
@@ -1,4 +1,6 @@
type Nullable<T> = T | null | undefined
declare const __doNotImplementIt: unique symbol
type __doNotImplementIt = typeof __doNotImplementIt
export namespace foo {
const prop: number;
class C {
@@ -1,5 +1,7 @@
declare namespace JS_TESTS {
type Nullable<T> = T | null | undefined
const __doNotImplementIt: unique symbol
type __doNotImplementIt = typeof __doNotImplementIt
namespace foo {
const prop: number;
class C {
@@ -1,4 +1,6 @@
type Nullable<T> = T | null | undefined
declare const __doNotImplementIt: unique symbol
type __doNotImplementIt = typeof __doNotImplementIt
export namespace foo {
const prop: number;
class C {
@@ -1,5 +1,7 @@
declare namespace JS_TESTS {
type Nullable<T> = T | null | undefined
const __doNotImplementIt: unique symbol
type __doNotImplementIt = typeof __doNotImplementIt
namespace foo.bar.baz {
class C1 {
constructor(value: string);
@@ -1,5 +1,7 @@
declare namespace JS_TESTS {
type Nullable<T> = T | null | undefined
const __doNotImplementIt: unique symbol
type __doNotImplementIt = typeof __doNotImplementIt
namespace foo {
const _any: any;
const _throwable: Error;
@@ -1,5 +1,7 @@
declare namespace JS_TESTS {
type Nullable<T> = T | null | undefined
const __doNotImplementIt: unique symbol
type __doNotImplementIt = typeof __doNotImplementIt
namespace foo {
interface ExportedInternalInterface {
}
@@ -1,5 +1,7 @@
declare namespace JS_TESTS {
type Nullable<T> = T | null | undefined
const __doNotImplementIt: unique symbol
type __doNotImplementIt = typeof __doNotImplementIt
interface publicInterface {
}
const publicVal: number;