feat(KT-48814): represent all of the external declarations nullable properties as an optional fields inside d.ts.

This commit is contained in:
Artem Kobzar
2022-09-02 10:50:20 +00:00
committed by Space
parent a52d8f0364
commit 0bb0be8703
12 changed files with 41 additions and 8 deletions
@@ -59,6 +59,7 @@ class ExportedProperty(
val isField: Boolean = false,
val irGetter: IrFunction? = null,
val irSetter: IrFunction? = null,
val isOptional: Boolean = false
) : ExportedDeclaration()
// TODO: Cover all cases with frontend and disable error declarations
@@ -139,6 +139,9 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
specializeType: ExportedType? = null
): ExportedDeclaration {
val parentClass = property.parent as? IrClass
val isOptional = property.isEffectivelyExternal() &&
property.parent is IrClass &&
property.getter?.returnType?.isNullable() == true
return ExportedProperty(
name = property.getExportedIdentifier(),
@@ -149,7 +152,8 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
isProtected = property.visibility == DescriptorVisibilities.PROTECTED,
isField = parentClass?.isInterface == true,
irGetter = property.getter,
irSetter = property.setter
irSetter = property.setter,
isOptional = isOptional
)
}
@@ -133,7 +133,8 @@ class ExportModelToTsDeclarations {
""
} else {
val readonly = if (isMember && !mutable) "readonly " else ""
"$prefix$visibility$possibleStatic$keyword$readonly$memberName: $typeToTypeScript;"
val optional = if (isOptional) "?" else ""
"$prefix$visibility$possibleStatic$keyword$readonly$memberName$optional: $typeToTypeScript;"
}
}
}
@@ -25,7 +25,7 @@ object JsPlatformConfigurator : PlatformConfiguratorBase(
JsRuntimeAnnotationChecker,
JsDynamicDeclarationChecker,
JsExportAnnotationChecker,
JsExportDeclarationChecker
JsExportDeclarationChecker,
),
additionalCallCheckers = listOf(
JsModuleCallChecker,
@@ -2,8 +2,8 @@ declare namespace JS_TESTS {
type Nullable<T> = T | null | undefined
namespace foo {
interface I<T, S, U> {
x: T;
readonly y: S;
x?: T;
readonly y?: S;
z(u: U): void;
}
interface I2 {
@@ -1,5 +1,11 @@
declare namespace JS_TESTS {
type Nullable<T> = T | null | undefined
namespace foo {
interface OptionalFieldsInterface {
readonly required: number;
readonly notRequired?: Nullable<number>;
}
}
namespace foo {
interface TestInterface {
readonly value: string;
@@ -24,5 +30,6 @@ declare namespace JS_TESTS {
readonly __doNotUseOrImplementIt: foo.TestInterfaceImpl["__doNotUseOrImplementIt"] & foo.AnotherExportedInterface["__doNotUseOrImplementIt"];
}
function processInterface(test: foo.TestInterface): string;
function processOptionalInterface(a: foo.OptionalFieldsInterface): string;
}
}
@@ -30,4 +30,15 @@ class ChildTestInterfaceImpl(): TestInterfaceImpl("Test"), AnotherExportedInterf
@JsExport
fun processInterface(test: TestInterface): String {
return "Owner ${test.getOwnerName()} has value '${test.value}'"
}
@JsExport
external interface OptionalFieldsInterface {
val required: Int
val notRequired: Int?
}
@JsExport
fun processOptionalInterface(a: OptionalFieldsInterface): String {
return "${a.required}${a.notRequired ?: "unknown"}"
}
@@ -2,6 +2,7 @@
var TestInterfaceImpl = JS_TESTS.foo.TestInterfaceImpl;
var ChildTestInterfaceImpl = JS_TESTS.foo.ChildTestInterfaceImpl;
var processInterface = JS_TESTS.foo.processInterface;
var processOptionalInterface = JS_TESTS.foo.processOptionalInterface;
function assert(condition) {
if (!condition) {
throw "Assertion failed";
@@ -12,5 +13,8 @@ function box() {
assert(processInterface(new ChildTestInterfaceImpl()) === "Owner TestInterfaceImpl has value 'Test'");
// @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'");
assert(processOptionalInterface({ required: 4 }) == "4unknown");
assert(processOptionalInterface({ required: 4, notRequired: null }) == "4unknown");
assert(processOptionalInterface({ required: 4, notRequired: 5 }) == "45");
return "OK";
}
@@ -1,6 +1,7 @@
import TestInterfaceImpl = JS_TESTS.foo.TestInterfaceImpl;
import ChildTestInterfaceImpl = JS_TESTS.foo.ChildTestInterfaceImpl;
import processInterface = JS_TESTS.foo.processInterface;
import processOptionalInterface = JS_TESTS.foo.processOptionalInterface;
function assert(condition: boolean) {
if (!condition) {
@@ -15,5 +16,9 @@ function box(): string {
// @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'")
assert(processOptionalInterface({ required: 4 }) == "4unknown")
assert(processOptionalInterface({ required: 4, notRequired: null }) == "4unknown")
assert(processOptionalInterface({ required: 4, notRequired: 5 }) == "45")
return "OK";
}
@@ -2,7 +2,7 @@ declare namespace JS_TESTS {
type Nullable<T> = T | null | undefined
namespace foo {
interface Object {
readonly constructor: any;
readonly constructor?: any;
}
}
namespace foo {
@@ -2,7 +2,7 @@ declare namespace JS_TESTS {
type Nullable<T> = T | null | undefined
namespace foo {
interface Object {
readonly constructor: any;
readonly constructor?: any;
}
}
namespace foo {
@@ -200,4 +200,4 @@ public actual annotation class JsExport
@Target(AnnotationTarget.PROPERTY)
@SinceKotlin("1.6")
@Deprecated("This annotation is a temporal migration assistance and may be removed in the future releases, please consider filing an issue about the case where it is needed")
public annotation class EagerInitialization
public annotation class EagerInitialization