[K/JS] fix(Interface Export): prevent structural identity between two interfaces.
This commit is contained in:
@@ -51,14 +51,14 @@ data class ExportedConstructSignature(
|
||||
class ExportedProperty(
|
||||
val name: String,
|
||||
val type: ExportedType,
|
||||
val mutable: Boolean,
|
||||
val mutable: Boolean = true,
|
||||
val isMember: Boolean = false,
|
||||
val isStatic: Boolean = false,
|
||||
val isAbstract: Boolean,
|
||||
val isProtected: Boolean,
|
||||
val isField: Boolean,
|
||||
val irGetter: IrFunction?,
|
||||
val irSetter: IrFunction?,
|
||||
val isAbstract: Boolean = false,
|
||||
val isProtected: Boolean = false,
|
||||
val isField: Boolean = false,
|
||||
val irGetter: IrFunction? = null,
|
||||
val irSetter: IrFunction? = null,
|
||||
) : ExportedDeclaration()
|
||||
|
||||
|
||||
@@ -117,6 +117,7 @@ sealed class ExportedType {
|
||||
object Any : Primitive("any")
|
||||
object Unit : Primitive("void")
|
||||
object Nothing : Primitive("never")
|
||||
object UniqueSymbol : Primitive("unique symbol")
|
||||
}
|
||||
|
||||
sealed class LiteralType<T : Any>(val value: T) : ExportedType() {
|
||||
@@ -144,6 +145,8 @@ sealed class ExportedType {
|
||||
|
||||
class IntersectionType(val lhs: ExportedType, val rhs: ExportedType) : ExportedType()
|
||||
|
||||
class PropertyType(val container: ExportedType, val propertyName: ExportedType) : ExportedType()
|
||||
|
||||
class ImplicitlyExportedType(val type: ExportedType) : ExportedType() {
|
||||
override fun withNullability(nullable: Boolean) =
|
||||
ImplicitlyExportedType(type.withNullability(nullable))
|
||||
|
||||
+62
-19
@@ -22,11 +22,12 @@ import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.keysToMap
|
||||
|
||||
private const val magicPropertyName = "__doNotUseOrImplementIt"
|
||||
|
||||
class ExportModelGenerator(
|
||||
val context: JsIrBackendContext,
|
||||
val generateNamespacesForPackages: Boolean
|
||||
@@ -133,11 +134,10 @@ class ExportModelGenerator(
|
||||
val parentClass = property.parent as? IrClass
|
||||
|
||||
return ExportedProperty(
|
||||
property.getExportedIdentifier(),
|
||||
specializeType ?: exportType(property.getter!!.returnType),
|
||||
name = property.getExportedIdentifier(),
|
||||
type = specializeType ?: exportType(property.getter!!.returnType),
|
||||
mutable = property.isVar,
|
||||
isMember = parentClass != null,
|
||||
isStatic = false,
|
||||
isAbstract = parentClass?.isInterface == false && property.modality == Modality.ABSTRACT,
|
||||
isProtected = property.visibility == DescriptorVisibilities.PROTECTED,
|
||||
isField = parentClass?.isInterface == true,
|
||||
@@ -156,18 +156,7 @@ class ExportModelGenerator(
|
||||
val ordinal = enumEntries.getValue(irEnumEntry)
|
||||
|
||||
fun fakeProperty(name: String, type: ExportedType) =
|
||||
ExportedProperty(
|
||||
name = name,
|
||||
type = type,
|
||||
mutable = false,
|
||||
isMember = true,
|
||||
isStatic = false,
|
||||
isAbstract = false,
|
||||
isProtected = false,
|
||||
irGetter = null,
|
||||
irSetter = null,
|
||||
isField = false,
|
||||
)
|
||||
ExportedProperty(name = name, type = type, mutable = false, isMember = true)
|
||||
|
||||
val nameProperty = fakeProperty(
|
||||
name = "name",
|
||||
@@ -189,12 +178,9 @@ class ExportModelGenerator(
|
||||
mutable = false,
|
||||
isMember = true,
|
||||
isStatic = true,
|
||||
isAbstract = false,
|
||||
isProtected = parentClass.visibility == DescriptorVisibilities.PROTECTED,
|
||||
irGetter = context.mapping.enumEntryToGetInstanceFun[irEnumEntry]
|
||||
?: error("Unable to find get instance fun for ${field.fqNameWhenAvailable}"),
|
||||
irSetter = null,
|
||||
isField = false,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -324,12 +310,69 @@ class ExportModelGenerator(
|
||||
}
|
||||
}
|
||||
|
||||
if (klass.shouldContainImplementationOfMagicProperty()) {
|
||||
members.addMagicPropertyForInterfaceImplementation(klass)
|
||||
} else if (klass.shouldNotBeImplemented()) {
|
||||
members.addMagicInterfaceProperty(klass)
|
||||
}
|
||||
|
||||
return ExportedClassDeclarationsInfo(
|
||||
members,
|
||||
nestedClasses
|
||||
)
|
||||
}
|
||||
|
||||
private fun IrClass.shouldNotBeImplemented(): Boolean {
|
||||
return isInterface && !isExternal
|
||||
}
|
||||
|
||||
private fun IrClass.shouldContainImplementationOfMagicProperty(): Boolean {
|
||||
return !isExternal && superTypes.any {
|
||||
val superClass = it.classOrNull?.owner ?: return@any false
|
||||
superClass.isInterface && superClass.isExported(context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<ExportedDeclaration>.addMagicInterfaceProperty(klass: IrClass) {
|
||||
add(ExportedProperty(name = magicPropertyName, type = klass.generateTagType(), mutable = false, isMember = true, isField = true))
|
||||
}
|
||||
|
||||
private fun MutableList<ExportedDeclaration>.addMagicPropertyForInterfaceImplementation(klass: IrClass) {
|
||||
val superTypesToInheritanceMagicProperty = klass.superTypes.filter { it.shouldAddMagicPropertyOfSuper() }
|
||||
|
||||
if (superTypesToInheritanceMagicProperty.isEmpty()) return
|
||||
|
||||
val intersectionOfTypes = superTypesToInheritanceMagicProperty
|
||||
.map { ExportedType.PropertyType(exportType(it), ExportedType.LiteralType.StringLiteralType(magicPropertyName)) }
|
||||
.reduce(ExportedType::IntersectionType)
|
||||
.let { if (klass.shouldNotBeImplemented()) ExportedType.IntersectionType(klass.generateTagType(), it) else it }
|
||||
|
||||
add(ExportedProperty(name = magicPropertyName, type = intersectionOfTypes, mutable = false, isMember = true, isField = true))
|
||||
}
|
||||
|
||||
private fun IrType.shouldAddMagicPropertyOfSuper(): Boolean {
|
||||
return classOrNull?.owner?.isOwnMagicPropertyAdded() ?: false
|
||||
}
|
||||
|
||||
private fun IrClass.isOwnMagicPropertyAdded(): Boolean {
|
||||
if (!isExported(context)) return false
|
||||
return isInterface && !isExternal || superTypes.any { it.classOrNull?.owner?.isOwnMagicPropertyAdded() ?: false }
|
||||
}
|
||||
|
||||
private fun IrClass.generateTagType(): ExportedType {
|
||||
return ExportedType.InlineInterfaceType(
|
||||
listOf(
|
||||
ExportedProperty(
|
||||
name = getFqNameWithJsNameWhenAvailable(true).asString(),
|
||||
type = ExportedType.Primitive.UniqueSymbol,
|
||||
mutable = false,
|
||||
isMember = true,
|
||||
isField = true,
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun exportClass(
|
||||
klass: IrClass,
|
||||
members: List<ExportedDeclaration>,
|
||||
|
||||
+32
-62
@@ -15,9 +15,7 @@ import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.js.common.isValidES5Identifier
|
||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
|
||||
private const val declare = "declare"
|
||||
private const val Nullable = "Nullable"
|
||||
private const val doNotImplementIt = "__doNotImplementIt"
|
||||
private const val objects = "_objects_"
|
||||
private const val syntheticObjectNameSeparator = '$'
|
||||
|
||||
@@ -37,15 +35,9 @@ class ExportModelToTsDeclarations {
|
||||
get() = if (this == ModuleKind.PLAIN) " " else ""
|
||||
|
||||
fun generateTypeScript(name: String, module: ExportedModule): String {
|
||||
val declareKeyword = when (module.moduleKind) {
|
||||
ModuleKind.PLAIN -> ""
|
||||
else -> "$declare "
|
||||
}
|
||||
val types = """
|
||||
type $Nullable<T> = T | null | undefined
|
||||
${declareKeyword}const $doNotImplementIt: unique symbol
|
||||
type $doNotImplementIt = typeof $doNotImplementIt
|
||||
""".trimIndent().prependIndent(module.moduleKind.indent) + "\n"
|
||||
type $Nullable<T> = T | null | undefined
|
||||
""".trimIndent().prependIndent(module.moduleKind.indent) + "\n"
|
||||
|
||||
val declarationsDts = types + module.declarations.toTypeScript(module.moduleKind)
|
||||
|
||||
@@ -152,6 +144,7 @@ class ExportModelToTsDeclarations {
|
||||
isAbstract -> "abstract "
|
||||
else -> ""
|
||||
}
|
||||
|
||||
else -> "function "
|
||||
}
|
||||
|
||||
@@ -209,11 +202,8 @@ class ExportModelToTsDeclarations {
|
||||
mutable = false,
|
||||
isMember = maybeParentClass != null && !shouldRenderSeparatedAbstractClass,
|
||||
isStatic = !ir.isInner && maybeParentClass?.isObject == false,
|
||||
isAbstract = false,
|
||||
isProtected = ir.visibility == DescriptorVisibilities.PROTECTED,
|
||||
irGetter = irGetter,
|
||||
irSetter = null,
|
||||
isField = false,
|
||||
)
|
||||
|
||||
return if (!shouldRenderSeparatedAbstractClass) {
|
||||
@@ -247,16 +237,14 @@ class ExportModelToTsDeclarations {
|
||||
|
||||
val (memberObjects, nestedDeclarations) = nestedClasses.partition { it.couldBeProperty() }
|
||||
|
||||
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))
|
||||
}
|
||||
} + memberObjects
|
||||
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))
|
||||
}
|
||||
} + memberObjects
|
||||
|
||||
val (innerClasses, nonInnerClasses) = nestedDeclarations.partition { it.ir.isInner }
|
||||
val innerClassesProperties = innerClasses.map { it.toReadonlyProperty() }
|
||||
@@ -308,41 +296,16 @@ class ExportModelToTsDeclarations {
|
||||
return when {
|
||||
exportedInterfaces.isEmpty() && nonExportedInterfaces.isNotEmpty() ->
|
||||
" /* $superInterfacesKeyword $listOfNonExportedInterfaces */"
|
||||
|
||||
exportedInterfaces.isNotEmpty() -> {
|
||||
val nonExportedInterfacesTsString = if (nonExportedInterfaces.isNotEmpty()) "/*, $listOfNonExportedInterfaces */" else ""
|
||||
" $superInterfacesKeyword " + exportedInterfaces.joinToString(", ") { it.toTypeScript(indent) } + nonExportedInterfacesTsString
|
||||
}
|
||||
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
||||
private fun ExportedRegularClass.shouldNotBeImplemented(): Boolean {
|
||||
return (isInterface && !ir.isExternal) || superInterfaces.any { it is ExportedType.ClassType && !it.ir.isExternal }
|
||||
}
|
||||
|
||||
private fun List<ExportedDeclaration>.withMagicProperty(): List<ExportedDeclaration> {
|
||||
return plus(
|
||||
ExportedProperty(
|
||||
"__doNotUseIt",
|
||||
ExportedType.TypeParameter(doNotImplementIt),
|
||||
mutable = false,
|
||||
isMember = true,
|
||||
isStatic = false,
|
||||
isAbstract = false,
|
||||
isProtected = false,
|
||||
isField = true,
|
||||
irGetter = null,
|
||||
irSetter = null,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun IrClass.asNestedClassAccess(): String {
|
||||
val name = getJsNameOrKotlinName().identifier
|
||||
if (parent !is IrClass) return name
|
||||
return "${parentAsClass.asNestedClassAccess()}.$name"
|
||||
}
|
||||
|
||||
private fun ExportedClass.withProtectedConstructors(): ExportedRegularClass {
|
||||
return (this as ExportedRegularClass).copy(members = members.map {
|
||||
if (it !is ExportedConstructor || it.isProtected) {
|
||||
@@ -371,18 +334,7 @@ class ExportModelToTsDeclarations {
|
||||
ExportedType.TypeOf(innerClassReference)
|
||||
)
|
||||
|
||||
return ExportedProperty(
|
||||
name = name,
|
||||
type = type,
|
||||
mutable = false,
|
||||
isMember = true,
|
||||
isStatic = false,
|
||||
isAbstract = false,
|
||||
isProtected = false,
|
||||
isField = false,
|
||||
irGetter = null,
|
||||
irSetter = null
|
||||
)
|
||||
return ExportedProperty(name = name, type = type, mutable = false, isMember = true)
|
||||
}
|
||||
|
||||
private fun ExportedParameter.toTypeScript(indent: String): String {
|
||||
@@ -392,6 +344,12 @@ class ExportModelToTsDeclarations {
|
||||
return "$name$questionMark: $type"
|
||||
}
|
||||
|
||||
private fun IrClass.asNestedClassAccess(): String {
|
||||
val name = getJsNameOrKotlinName().identifier
|
||||
if (parent !is IrClass) return name
|
||||
return "${parentAsClass.asNestedClassAccess()}.$name"
|
||||
}
|
||||
|
||||
private fun ExportedType.toTypeScript(indent: String, isInCommentContext: Boolean = false): String = when (this) {
|
||||
is ExportedType.Primitive -> typescript
|
||||
is ExportedType.Array -> "Array<${elementType.toTypeScript(indent, isInCommentContext)}>"
|
||||
@@ -403,6 +361,7 @@ class ExportModelToTsDeclarations {
|
||||
|
||||
is ExportedType.ClassType ->
|
||||
name + if (arguments.isNotEmpty()) "<${arguments.joinToString(", ") { it.toTypeScript(indent, isInCommentContext) }}>" else ""
|
||||
|
||||
is ExportedType.TypeOf ->
|
||||
"typeof $name"
|
||||
|
||||
@@ -411,18 +370,29 @@ class ExportModelToTsDeclarations {
|
||||
is ExportedType.InlineInterfaceType -> {
|
||||
members.joinToString(prefix = "{\n", postfix = "$indent}", separator = "") { it.toTypeScript("$indent ") + "\n" }
|
||||
}
|
||||
|
||||
is ExportedType.IntersectionType -> {
|
||||
lhs.toTypeScript(indent) + " & " + rhs.toTypeScript(indent, isInCommentContext)
|
||||
}
|
||||
|
||||
is ExportedType.UnionType -> {
|
||||
lhs.toTypeScript(indent) + " | " + rhs.toTypeScript(indent, isInCommentContext)
|
||||
}
|
||||
|
||||
is ExportedType.LiteralType.StringLiteralType -> "\"$value\""
|
||||
is ExportedType.LiteralType.NumberLiteralType -> value.toString()
|
||||
is ExportedType.ImplicitlyExportedType -> {
|
||||
val typeString = type.toTypeScript("", true)
|
||||
if (isInCommentContext) typeString else ExportedType.Primitive.Any.toTypeScript(indent) + "/* $typeString */"
|
||||
}
|
||||
|
||||
is ExportedType.PropertyType -> "${container.toTypeScript(indent, isInCommentContext)}[${
|
||||
propertyName.toTypeScript(
|
||||
indent,
|
||||
isInCommentContext
|
||||
)
|
||||
}]"
|
||||
|
||||
is ExportedType.TypeParameter -> if (constraint == null) {
|
||||
name
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
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,7 +1,5 @@
|
||||
declare namespace JS_TESTS {
|
||||
type Nullable<T> = T | null | undefined
|
||||
const __doNotImplementIt: unique symbol
|
||||
type __doNotImplementIt = typeof __doNotImplementIt
|
||||
class ClassWithDefaultCtor {
|
||||
constructor();
|
||||
get x(): string;
|
||||
|
||||
+13
-4
@@ -1,7 +1,5 @@
|
||||
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;
|
||||
@@ -138,13 +136,24 @@ declare namespace JS_TESTS {
|
||||
interface TestInterface {
|
||||
readonly value: string;
|
||||
getOwnerName(): string;
|
||||
readonly __doNotUseIt: __doNotImplementIt;
|
||||
readonly __doNotUseOrImplementIt: {
|
||||
readonly "foo.TestInterface": unique symbol;
|
||||
};
|
||||
}
|
||||
interface AnotherExportedInterface {
|
||||
readonly __doNotUseOrImplementIt: {
|
||||
readonly "foo.AnotherExportedInterface": unique symbol;
|
||||
};
|
||||
}
|
||||
class TestInterfaceImpl implements foo.TestInterface {
|
||||
constructor(value: string);
|
||||
get value(): string;
|
||||
getOwnerName(): string;
|
||||
readonly __doNotUseIt: __doNotImplementIt;
|
||||
readonly __doNotUseOrImplementIt: foo.TestInterface["__doNotUseOrImplementIt"];
|
||||
}
|
||||
class ChildTestInterfaceImpl extends foo.TestInterfaceImpl implements foo.AnotherExportedInterface {
|
||||
constructor();
|
||||
readonly __doNotUseOrImplementIt: foo.TestInterfaceImpl["__doNotUseOrImplementIt"] & foo.AnotherExportedInterface["__doNotUseOrImplementIt"];
|
||||
}
|
||||
function processInterface(test: foo.TestInterface): string;
|
||||
class OuterClass {
|
||||
|
||||
@@ -202,10 +202,16 @@ interface TestInterface {
|
||||
}
|
||||
|
||||
@JsExport
|
||||
class TestInterfaceImpl(override val value: String) : TestInterface {
|
||||
interface AnotherExportedInterface
|
||||
|
||||
@JsExport
|
||||
open class TestInterfaceImpl(override val value: String) : TestInterface {
|
||||
override fun getOwnerName() = "TestInterfaceImpl"
|
||||
}
|
||||
|
||||
@JsExport
|
||||
class ChildTestInterfaceImpl(): TestInterfaceImpl("Test"), AnotherExportedInterface
|
||||
|
||||
@JsExport
|
||||
fun processInterface(test: TestInterface): String {
|
||||
return "Owner ${test.getOwnerName()} has value '${test.value}'"
|
||||
|
||||
-2
@@ -1,7 +1,5 @@
|
||||
declare namespace JS_TESTS {
|
||||
type Nullable<T> = T | null | undefined
|
||||
const __doNotImplementIt: unique symbol
|
||||
type __doNotImplementIt = typeof __doNotImplementIt
|
||||
namespace foo {
|
||||
|
||||
|
||||
|
||||
+5
-5
@@ -1,10 +1,10 @@
|
||||
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;
|
||||
readonly __doNotUseOrImplementIt: {
|
||||
readonly "foo.ExportedInterface": unique symbol;
|
||||
};
|
||||
}
|
||||
function producer(value: number): any/* foo.NonExportedType */;
|
||||
function consumer(value: any/* foo.NonExportedType */): number;
|
||||
@@ -22,11 +22,11 @@ declare namespace JS_TESTS {
|
||||
}
|
||||
class D implements foo.ExportedInterface/*, foo.NonExportedInterface */ {
|
||||
constructor();
|
||||
readonly __doNotUseIt: __doNotImplementIt;
|
||||
readonly __doNotUseOrImplementIt: foo.ExportedInterface["__doNotUseOrImplementIt"];
|
||||
}
|
||||
class E /* extends foo.NonExportedType */ implements foo.ExportedInterface {
|
||||
constructor();
|
||||
readonly __doNotUseIt: __doNotImplementIt;
|
||||
readonly __doNotUseOrImplementIt: foo.ExportedInterface["__doNotUseOrImplementIt"];
|
||||
}
|
||||
class F extends foo.A /* implements foo.NonExportedInterface */ {
|
||||
constructor();
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
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;
|
||||
@@ -43,7 +41,9 @@ declare namespace JS_TESTS {
|
||||
bar: string;
|
||||
readonly baz: string;
|
||||
bay(): string;
|
||||
readonly __doNotUseIt: __doNotImplementIt;
|
||||
readonly __doNotUseOrImplementIt: {
|
||||
readonly "foo.I3": unique symbol;
|
||||
};
|
||||
}
|
||||
function getI3(): foo.I3;
|
||||
function getA(): foo.I3;
|
||||
@@ -56,7 +56,7 @@ declare namespace JS_TESTS {
|
||||
abstract set bar(value: string);
|
||||
abstract get baz(): string;
|
||||
abstract bay(): string;
|
||||
readonly __doNotUseIt: __doNotImplementIt;
|
||||
readonly __doNotUseOrImplementIt: foo.I3["__doNotUseOrImplementIt"];
|
||||
}
|
||||
class B2 extends foo.A2 {
|
||||
constructor();
|
||||
@@ -98,7 +98,7 @@ declare namespace JS_TESTS {
|
||||
get name(): "EC1" | "EC2" | "EC3";
|
||||
get ordinal(): 0 | 1 | 2;
|
||||
abstract get baz(): string;
|
||||
readonly __doNotUseIt: __doNotImplementIt;
|
||||
readonly __doNotUseOrImplementIt: foo.I3["__doNotUseOrImplementIt"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
type Nullable<T> = T | null | undefined
|
||||
declare const __doNotImplementIt: unique symbol
|
||||
type __doNotImplementIt = typeof __doNotImplementIt
|
||||
export namespace foo {
|
||||
const prop: number;
|
||||
class C {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
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,6 +1,4 @@
|
||||
type Nullable<T> = T | null | undefined
|
||||
declare const __doNotImplementIt: unique symbol
|
||||
type __doNotImplementIt = typeof __doNotImplementIt
|
||||
export namespace foo {
|
||||
const prop: number;
|
||||
class C {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
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,7 +1,5 @@
|
||||
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;
|
||||
|
||||
-2
@@ -1,7 +1,5 @@
|
||||
declare namespace JS_TESTS {
|
||||
type Nullable<T> = T | null | undefined
|
||||
const __doNotImplementIt: unique symbol
|
||||
type __doNotImplementIt = typeof __doNotImplementIt
|
||||
namespace foo {
|
||||
interface ExportedInternalInterface {
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
declare namespace JS_TESTS {
|
||||
type Nullable<T> = T | null | undefined
|
||||
const __doNotImplementIt: unique symbol
|
||||
type __doNotImplementIt = typeof __doNotImplementIt
|
||||
interface publicInterface {
|
||||
}
|
||||
const publicVal: number;
|
||||
|
||||
Reference in New Issue
Block a user