feat(KT-48814): represent all of the external declarations nullable properties as an optional fields inside d.ts.
This commit is contained in:
@@ -59,6 +59,7 @@ class ExportedProperty(
|
|||||||
val isField: Boolean = false,
|
val isField: Boolean = false,
|
||||||
val irGetter: IrFunction? = null,
|
val irGetter: IrFunction? = null,
|
||||||
val irSetter: IrFunction? = null,
|
val irSetter: IrFunction? = null,
|
||||||
|
val isOptional: Boolean = false
|
||||||
) : ExportedDeclaration()
|
) : ExportedDeclaration()
|
||||||
|
|
||||||
// TODO: Cover all cases with frontend and disable error declarations
|
// TODO: Cover all cases with frontend and disable error declarations
|
||||||
|
|||||||
+5
-1
@@ -139,6 +139,9 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
|
|||||||
specializeType: ExportedType? = null
|
specializeType: ExportedType? = null
|
||||||
): ExportedDeclaration {
|
): ExportedDeclaration {
|
||||||
val parentClass = property.parent as? IrClass
|
val parentClass = property.parent as? IrClass
|
||||||
|
val isOptional = property.isEffectivelyExternal() &&
|
||||||
|
property.parent is IrClass &&
|
||||||
|
property.getter?.returnType?.isNullable() == true
|
||||||
|
|
||||||
return ExportedProperty(
|
return ExportedProperty(
|
||||||
name = property.getExportedIdentifier(),
|
name = property.getExportedIdentifier(),
|
||||||
@@ -149,7 +152,8 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
|
|||||||
isProtected = property.visibility == DescriptorVisibilities.PROTECTED,
|
isProtected = property.visibility == DescriptorVisibilities.PROTECTED,
|
||||||
isField = parentClass?.isInterface == true,
|
isField = parentClass?.isInterface == true,
|
||||||
irGetter = property.getter,
|
irGetter = property.getter,
|
||||||
irSetter = property.setter
|
irSetter = property.setter,
|
||||||
|
isOptional = isOptional
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -133,7 +133,8 @@ class ExportModelToTsDeclarations {
|
|||||||
""
|
""
|
||||||
} else {
|
} else {
|
||||||
val readonly = if (isMember && !mutable) "readonly " 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,
|
JsRuntimeAnnotationChecker,
|
||||||
JsDynamicDeclarationChecker,
|
JsDynamicDeclarationChecker,
|
||||||
JsExportAnnotationChecker,
|
JsExportAnnotationChecker,
|
||||||
JsExportDeclarationChecker
|
JsExportDeclarationChecker,
|
||||||
),
|
),
|
||||||
additionalCallCheckers = listOf(
|
additionalCallCheckers = listOf(
|
||||||
JsModuleCallChecker,
|
JsModuleCallChecker,
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ declare namespace JS_TESTS {
|
|||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
namespace foo {
|
namespace foo {
|
||||||
interface I<T, S, U> {
|
interface I<T, S, U> {
|
||||||
x: T;
|
x?: T;
|
||||||
readonly y: S;
|
readonly y?: S;
|
||||||
z(u: U): void;
|
z(u: U): void;
|
||||||
}
|
}
|
||||||
interface I2 {
|
interface I2 {
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
declare namespace JS_TESTS {
|
declare namespace JS_TESTS {
|
||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
|
namespace foo {
|
||||||
|
interface OptionalFieldsInterface {
|
||||||
|
readonly required: number;
|
||||||
|
readonly notRequired?: Nullable<number>;
|
||||||
|
}
|
||||||
|
}
|
||||||
namespace foo {
|
namespace foo {
|
||||||
interface TestInterface {
|
interface TestInterface {
|
||||||
readonly value: string;
|
readonly value: string;
|
||||||
@@ -24,5 +30,6 @@ declare namespace JS_TESTS {
|
|||||||
readonly __doNotUseOrImplementIt: foo.TestInterfaceImpl["__doNotUseOrImplementIt"] & foo.AnotherExportedInterface["__doNotUseOrImplementIt"];
|
readonly __doNotUseOrImplementIt: foo.TestInterfaceImpl["__doNotUseOrImplementIt"] & foo.AnotherExportedInterface["__doNotUseOrImplementIt"];
|
||||||
}
|
}
|
||||||
function processInterface(test: foo.TestInterface): string;
|
function processInterface(test: foo.TestInterface): string;
|
||||||
|
function processOptionalInterface(a: foo.OptionalFieldsInterface): string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,4 +30,15 @@ class ChildTestInterfaceImpl(): TestInterfaceImpl("Test"), AnotherExportedInterf
|
|||||||
@JsExport
|
@JsExport
|
||||||
fun processInterface(test: TestInterface): String {
|
fun processInterface(test: TestInterface): String {
|
||||||
return "Owner ${test.getOwnerName()} has value '${test.value}'"
|
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 TestInterfaceImpl = JS_TESTS.foo.TestInterfaceImpl;
|
||||||
var ChildTestInterfaceImpl = JS_TESTS.foo.ChildTestInterfaceImpl;
|
var ChildTestInterfaceImpl = JS_TESTS.foo.ChildTestInterfaceImpl;
|
||||||
var processInterface = JS_TESTS.foo.processInterface;
|
var processInterface = JS_TESTS.foo.processInterface;
|
||||||
|
var processOptionalInterface = JS_TESTS.foo.processOptionalInterface;
|
||||||
function assert(condition) {
|
function assert(condition) {
|
||||||
if (!condition) {
|
if (!condition) {
|
||||||
throw "Assertion failed";
|
throw "Assertion failed";
|
||||||
@@ -12,5 +13,8 @@ function box() {
|
|||||||
assert(processInterface(new ChildTestInterfaceImpl()) === "Owner TestInterfaceImpl has value 'Test'");
|
assert(processInterface(new ChildTestInterfaceImpl()) === "Owner TestInterfaceImpl has value 'Test'");
|
||||||
// @ts-expect-error "Just test that this code will throw compilation error for a user"
|
// @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(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";
|
return "OK";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import TestInterfaceImpl = JS_TESTS.foo.TestInterfaceImpl;
|
import TestInterfaceImpl = JS_TESTS.foo.TestInterfaceImpl;
|
||||||
import ChildTestInterfaceImpl = JS_TESTS.foo.ChildTestInterfaceImpl;
|
import ChildTestInterfaceImpl = JS_TESTS.foo.ChildTestInterfaceImpl;
|
||||||
import processInterface = JS_TESTS.foo.processInterface;
|
import processInterface = JS_TESTS.foo.processInterface;
|
||||||
|
import processOptionalInterface = JS_TESTS.foo.processOptionalInterface;
|
||||||
|
|
||||||
function assert(condition: boolean) {
|
function assert(condition: boolean) {
|
||||||
if (!condition) {
|
if (!condition) {
|
||||||
@@ -15,5 +16,9 @@ function box(): string {
|
|||||||
// @ts-expect-error "Just test that this code will throw compilation error for a user"
|
// @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(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";
|
return "OK";
|
||||||
}
|
}
|
||||||
+1
-1
@@ -2,7 +2,7 @@ declare namespace JS_TESTS {
|
|||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
namespace foo {
|
namespace foo {
|
||||||
interface Object {
|
interface Object {
|
||||||
readonly constructor: any;
|
readonly constructor?: any;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
namespace foo {
|
namespace foo {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ declare namespace JS_TESTS {
|
|||||||
type Nullable<T> = T | null | undefined
|
type Nullable<T> = T | null | undefined
|
||||||
namespace foo {
|
namespace foo {
|
||||||
interface Object {
|
interface Object {
|
||||||
readonly constructor: any;
|
readonly constructor?: any;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
namespace foo {
|
namespace foo {
|
||||||
|
|||||||
@@ -200,4 +200,4 @@ public actual annotation class JsExport
|
|||||||
@Target(AnnotationTarget.PROPERTY)
|
@Target(AnnotationTarget.PROPERTY)
|
||||||
@SinceKotlin("1.6")
|
@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")
|
@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
|
||||||
Reference in New Issue
Block a user