From ef12e6bc7929868fd89b70a49696637c001d44b6 Mon Sep 17 00:00:00 2001 From: viktorsperling Date: Fri, 23 Jan 2026 13:31:41 +0100 Subject: [PATCH 1/7] revert(dts-generator): revert add getOriginalProperty declarations and tests to TypedJSONModel This reverts commit ae4ba2eec5359cee8d4153624c555a25876dd33e. --- .../src/resources/typed-json-model.d.ts | 10 ------- .../typed-json-model/webapp/model/model.ts | 17 ------------ .../test/cases/absolute-complex-inference.ts | 26 ------------------- .../test/cases/absolute-complex-interface.ts | 26 ------------------- .../test/cases/absolute-complex-typeAlias.ts | 26 ------------------- .../cases/absolute-primitive-inference.ts | 21 --------------- .../cases/absolute-primitive-interface.ts | 21 --------------- .../cases/absolute-primitive-typeAilas.ts | 21 --------------- .../webapp/model/test/cases/edgeCases.ts | 3 --- .../test/cases/relative-complex-inference.ts | 26 ------------------- .../test/cases/relative-complex-interface.ts | 26 ------------------- .../test/cases/relative-complex-typeAlias.ts | 26 ------------------- .../cases/relative-primitive-inference.ts | 21 --------------- .../cases/relative-primitive-interface.ts | 21 --------------- .../cases/relative-primitive-typeAlias.ts | 21 --------------- 15 files changed, 312 deletions(-) diff --git a/packages/dts-generator/src/resources/typed-json-model.d.ts b/packages/dts-generator/src/resources/typed-json-model.d.ts index 32f33ad..5d33d33 100644 --- a/packages/dts-generator/src/resources/typed-json-model.d.ts +++ b/packages/dts-generator/src/resources/typed-json-model.d.ts @@ -29,16 +29,6 @@ declare module "sap/ui/model/json/TypedJSONModel" { sPath: Path, oContext: TypedJSONContext, ): PropertyByRelativeBindingPath; - getOriginalProperty>( - sPath: Path, - ): PropertyByAbsoluteBindingPath; - getOriginalProperty< - Path extends RelativeBindingPath, - Root extends AbsoluteBindingPath, - >( - sPath: Path, - oContext: TypedJSONContext, - ): PropertyByRelativeBindingPath; setData(oData: Data, bMerge?: boolean): void; diff --git a/test-packages/typed-json-model/webapp/model/model.ts b/test-packages/typed-json-model/webapp/model/model.ts index 19666d9..a3b70ad 100644 --- a/test-packages/typed-json-model/webapp/model/model.ts +++ b/test-packages/typed-json-model/webapp/model/model.ts @@ -57,23 +57,6 @@ export class TypedJSONModel extends JSONModel { | PropertyByRelativeBindingPath; } - getOriginalProperty>(sPath: Path): PropertyByAbsoluteBindingPath; - getOriginalProperty, Root extends AbsoluteBindingPath>( - sPath: Path, - oContext: TypedJSONContext, - ): PropertyByRelativeBindingPath; - getOriginalProperty< - Path extends AbsoluteBindingPath | RelativeBindingPath, - Root extends AbsoluteBindingPath, - >( - sPath: Path, - oContext?: TypedJSONContext, - ): PropertyByAbsoluteBindingPath | PropertyByRelativeBindingPath { - return super.getOriginalProperty(sPath, oContext) as - | PropertyByAbsoluteBindingPath - | PropertyByRelativeBindingPath; - } - setData(oData: Data, bMerge?: boolean): void { super.setData(oData, bMerge); } diff --git a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-inference.ts b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-inference.ts index 6fb8f61..6a37cff 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-inference.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-inference.ts @@ -67,32 +67,6 @@ import { TypedJSONModel } from "../../model"; /** @expect ts2322 */ anElementInATuple = model.getProperty("/aTuple"); /** @expect ts2322 */ anObject = model.getProperty("/aTuple/0"); -/*********************************************************************************************************************** - * Check model.getOriginalProperty - **********************************************************************************************************************/ - -/** @expect ok */ anObject = model.getOriginalProperty("/anObject"); -/** @expect ok */ anArray = model.getOriginalProperty("/anArray"); -/** @expect ok */ aJsonSafeArray = model.getOriginalProperty("/aJsonSafeArray"); -/** @expect ok */ aJsonSafe = model.getOriginalProperty("/aJsonSafeArray/0"); -/** @expect ok */ aPlaceholder = model.getOriginalProperty("/aPlaceholder"); -/** @expect ok */ anArrayOfPlaceholders = model.getOriginalProperty("/anArrayOfPlaceholders"); -/** @expect ok */ anotherPlaceholder = model.getOriginalProperty("/anArrayOfPlaceholders/0"); -/** @expect ok */ aTuple = model.getOriginalProperty("/aTuple"); -/** @expect ok */ anElementInATuple = model.getOriginalProperty("/aTuple/0"); - -/** @expect ts2345 */ anything = model.getOriginalProperty("/anObject/0"); -/** @expect ts2345 */ anything = model.getOriginalProperty("/doesNotExist"); -/** @expect ts2345 */ anything = model.getOriginalProperty("/anArray/0/doesNotExist"); - -/** @expect ts2739 */ aPlaceholder = model.getOriginalProperty("/anObject"); -/** @expect ts2322 */ anArrayOfPlaceholders = model.getOriginalProperty("/aJsonSafeArray"); -/** @expect ts2322 */ anObject = model.getOriginalProperty("/aJsonSafeArray/0"); -/** @expect ts2322 */ aJsonSafe = model.getOriginalProperty("/aPlaceholder"); -/** @expect ts2322 */ aJsonSafe = model.getOriginalProperty("/anArrayOfPlaceholders/0"); -/** @expect ts2322 */ anElementInATuple = model.getOriginalProperty("/aTuple"); -/** @expect ts2322 */ anObject = model.getOriginalProperty("/aTuple/0"); - /*********************************************************************************************************************** * Check model.getData / model.setData **********************************************************************************************************************/ diff --git a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-interface.ts b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-interface.ts index 5638804..142b3b8 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-interface.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-interface.ts @@ -71,32 +71,6 @@ import { TypedJSONModel } from "../../model"; /** @expect ts2322 */ anElementInATuple = model.getProperty("/aTuple"); /** @expect ts2322 */ anObject = model.getProperty("/aTuple/0"); -/*********************************************************************************************************************** - * Check model.getOriginalProperty - **********************************************************************************************************************/ - -/** @expect ok */ anObject = model.getOriginalProperty("/anObject"); -/** @expect ok */ anArray = model.getOriginalProperty("/anArray"); -/** @expect ok */ aJsonSafeArray = model.getOriginalProperty("/aJsonSafeArray"); -/** @expect ok */ aJsonSafe = model.getOriginalProperty("/aJsonSafeArray/0"); -/** @expect ok */ aPlaceholder = model.getOriginalProperty("/aPlaceholder"); -/** @expect ok */ anArrayOfPlaceholders = model.getOriginalProperty("/anArrayOfPlaceholders"); -/** @expect ok */ anotherPlaceholder = model.getOriginalProperty("/anArrayOfPlaceholders/0"); -/** @expect ok */ aTuple = model.getOriginalProperty("/aTuple"); -/** @expect ok */ anElementInATuple = model.getOriginalProperty("/aTuple/0"); - -/** @expect ts2345 */ anything = model.getOriginalProperty("/anObject/0"); -/** @expect ts2345 */ anything = model.getOriginalProperty("/doesNotExist"); -/** @expect ts2345 */ anything = model.getOriginalProperty("/anArray/0/doesNotExist"); - -/** @expect ts2739 */ aPlaceholder = model.getOriginalProperty("/anObject"); -/** @expect ts2322 */ anArrayOfPlaceholders = model.getOriginalProperty("/aJsonSafeArray"); -/** @expect ts2322 */ anObject = model.getOriginalProperty("/aJsonSafeArray/0"); -/** @expect ts2322 */ aJsonSafe = model.getOriginalProperty("/aPlaceholder"); -/** @expect ts2322 */ aJsonSafe = model.getOriginalProperty("/anArrayOfPlaceholders/0"); -/** @expect ts2322 */ anElementInATuple = model.getOriginalProperty("/aTuple"); -/** @expect ts2322 */ anObject = model.getOriginalProperty("/aTuple/0"); - /*********************************************************************************************************************** * Check model.getData / model.setData **********************************************************************************************************************/ diff --git a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-typeAlias.ts b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-typeAlias.ts index 584bd74..ab91bbc 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-typeAlias.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-typeAlias.ts @@ -71,32 +71,6 @@ import { TypedJSONModel } from "../../model"; /** @expect ts2322 */ anElementInATuple = model.getProperty("/aTuple"); /** @expect ts2322 */ anObject = model.getProperty("/aTuple/0"); -/*********************************************************************************************************************** - * Check model.getOriginalProperty - **********************************************************************************************************************/ - -/** @expect ok */ anObject = model.getOriginalProperty("/anObject"); -/** @expect ok */ anArray = model.getOriginalProperty("/anArray"); -/** @expect ok */ aJsonSafeArray = model.getOriginalProperty("/aJsonSafeArray"); -/** @expect ok */ aJsonSafe = model.getOriginalProperty("/aJsonSafeArray/0"); -/** @expect ok */ aPlaceholder = model.getOriginalProperty("/aPlaceholder"); -/** @expect ok */ anArrayOfPlaceholders = model.getOriginalProperty("/anArrayOfPlaceholders"); -/** @expect ok */ anotherPlaceholder = model.getOriginalProperty("/anArrayOfPlaceholders/0"); -/** @expect ok */ aTuple = model.getOriginalProperty("/aTuple"); -/** @expect ok */ anElementInATuple = model.getOriginalProperty("/aTuple/0"); - -/** @expect ts2345 */ anything = model.getOriginalProperty("/anObject/0"); -/** @expect ts2345 */ anything = model.getOriginalProperty("/doesNotExist"); -/** @expect ts2345 */ anything = model.getOriginalProperty("/anArray/0/doesNotExist"); - -/** @expect ts2739 */ aPlaceholder = model.getOriginalProperty("/anObject"); -/** @expect ts2322 */ anArrayOfPlaceholders = model.getOriginalProperty("/aJsonSafeArray"); -/** @expect ts2322 */ anObject = model.getOriginalProperty("/aJsonSafeArray/0"); -/** @expect ts2322 */ aJsonSafe = model.getOriginalProperty("/aPlaceholder"); -/** @expect ts2322 */ aJsonSafe = model.getOriginalProperty("/anArrayOfPlaceholders/0"); -/** @expect ts2322 */ anElementInATuple = model.getOriginalProperty("/aTuple"); -/** @expect ts2322 */ anObject = model.getOriginalProperty("/aTuple/0"); - /*********************************************************************************************************************** * Check model.getData / model.setData **********************************************************************************************************************/ diff --git a/test-packages/typed-json-model/webapp/model/test/cases/absolute-primitive-inference.ts b/test-packages/typed-json-model/webapp/model/test/cases/absolute-primitive-inference.ts index 279bcb9..6beb3ca 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/absolute-primitive-inference.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/absolute-primitive-inference.ts @@ -54,24 +54,3 @@ let aSymbol: symbol = Symbol("test"); // value is a symbol -> not JSON serializable! /** @expect ts2322 */ aSymbol = model.getProperty("/aSymbol"); - -/*********************************************************************************************************************** - * Check model.getOriginalProperty - **********************************************************************************************************************/ - -/** @expect ok */ aString = model.getOriginalProperty("/aString"); -/** @expect ok */ aNumber = model.getOriginalProperty("/aNumber"); -/** @expect ok */ aBoolean = model.getOriginalProperty("/aBoolean"); -/** @expect ok */ aNull = model.getOriginalProperty("/aNull"); -/** @expect ok */ anUndefined = model.getOriginalProperty("/anUndefined"); - -/** @expect ts2345 */ const test1 = model.getOriginalProperty("/doesNotExist"); - -/** @expect ts2322 */ aNumber = model.getOriginalProperty("/aString"); -/** @expect ts2322 */ aString = model.getOriginalProperty("/aNumber"); -/** @expect ts2322 */ anUndefined = model.getOriginalProperty("/aNull"); -/** @expect ts2322 */ aNull = model.getOriginalProperty("/anUndefined"); -/** @expect ts2322 */ aBoolean = model.getOriginalProperty("/aDate"); - -// value is a symbol -> not JSON serializable! -/** @expect ts2322 */ aSymbol = model.getOriginalProperty("/aSymbol"); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/absolute-primitive-interface.ts b/test-packages/typed-json-model/webapp/model/test/cases/absolute-primitive-interface.ts index 183a5ef..8636648 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/absolute-primitive-interface.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/absolute-primitive-interface.ts @@ -54,24 +54,3 @@ let aSymbol: symbol = Symbol("test"); // value is a symbol -> not JSON serializable! /** @expect ts2322 */ aSymbol = model.getProperty("/aSymbol"); - -/*********************************************************************************************************************** - * Check model.getOriginalProperty - **********************************************************************************************************************/ - -/** @expect ok */ aString = model.getOriginalProperty("/aString"); -/** @expect ok */ aNumber = model.getOriginalProperty("/aNumber"); -/** @expect ok */ aBoolean = model.getOriginalProperty("/aBoolean"); -/** @expect ok */ aNull = model.getOriginalProperty("/aNull"); -/** @expect ok */ anUndefined = model.getOriginalProperty("/anUndefined"); - -/** @expect ts2345 */ const test1 = model.getOriginalProperty("/doesNotExist"); - -/** @expect ts2322 */ aNumber = model.getOriginalProperty("/aString"); -/** @expect ts2322 */ aString = model.getOriginalProperty("/aNumber"); -/** @expect ts2322 */ anUndefined = model.getOriginalProperty("/aNull"); -/** @expect ts2322 */ aNull = model.getOriginalProperty("/anUndefined"); -/** @expect ts2322 */ aBoolean = model.getOriginalProperty("/aDate"); - -// value is a symbol -> not JSON serializable! -/** @expect ts2322 */ aSymbol = model.getOriginalProperty("/aSymbol"); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/absolute-primitive-typeAilas.ts b/test-packages/typed-json-model/webapp/model/test/cases/absolute-primitive-typeAilas.ts index e49a9ba..d07cd17 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/absolute-primitive-typeAilas.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/absolute-primitive-typeAilas.ts @@ -54,24 +54,3 @@ let aSymbol: symbol = Symbol("test"); // value is a symbol -> not JSON serializable! /** @expect ts2322 */ aSymbol = model.getProperty("/aSymbol"); - -/*********************************************************************************************************************** - * Check model.getOriginalProperty - **********************************************************************************************************************/ - -/** @expect ok */ aString = model.getOriginalProperty("/aString"); -/** @expect ok */ aNumber = model.getOriginalProperty("/aNumber"); -/** @expect ok */ aBoolean = model.getOriginalProperty("/aBoolean"); -/** @expect ok */ aNull = model.getOriginalProperty("/aNull"); -/** @expect ok */ anUndefined = model.getOriginalProperty("/anUndefined"); - -/** @expect ts2345 */ const test1 = model.getOriginalProperty("/doesNotExist"); - -/** @expect ts2322 */ aNumber = model.getOriginalProperty("/aString"); -/** @expect ts2322 */ aString = model.getOriginalProperty("/aNumber"); -/** @expect ts2322 */ anUndefined = model.getOriginalProperty("/aNull"); -/** @expect ts2322 */ aNull = model.getOriginalProperty("/anUndefined"); -/** @expect ts2322 */ aBoolean = model.getOriginalProperty("/aDate"); - -// value is a symbol -> not JSON serializable! -/** @expect ts2322 */ aSymbol = model.getOriginalProperty("/aSymbol"); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/edgeCases.ts b/test-packages/typed-json-model/webapp/model/test/cases/edgeCases.ts index 50c0fd2..43fe5e6 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/edgeCases.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/edgeCases.ts @@ -12,7 +12,6 @@ const array = [1, 2, 3]; /** @expect ok */ const model1 = new TypedJSONModel(array); /** @expect ok */ let someNumber: number = model1.getProperty("/0"); -/** @expect ok */ let anOriginalNumber: number = model1.getOriginalProperty("/0"); /** @expect ok */ model1.setProperty("/0", 42); /** @expect ts2345 */ model1.setProperty("/0", "42"); @@ -23,9 +22,7 @@ const model2 = new TypedJSONModel([] as TestArray); /** @expect ok */ const someObject: { aNumber: number } = model2.getProperty("/0"); /** @expect ok */ someNumber = model2.getProperty("/0/aNumber"); -/** @expect ok */ anOriginalNumber = model2.getOriginalProperty("/0/aNumber"); /** @expect ts2322 */ const someString: string = model2.getProperty("/0"); -/** @expect ts2322 */ const anOriginalString: string = model2.getOriginalProperty("/0"); /** @expect ok */ model2.setProperty("/0", { aNumber: 42 }); /** @expect ts2345 */ model2.setProperty("/0", {}); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-inference.ts b/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-inference.ts index 1ceb74d..b730283 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-inference.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-inference.ts @@ -67,29 +67,3 @@ import { TypedJSONModel } from "../../model"; /** @expect ts2322 */ aJsonSafe = model.getProperty("anArrayOfPlaceholders/0", context); /** @expect ts2322 */ anElementInATuple = model.getProperty("aTuple", context); /** @expect ts2322 */ anObject = model.getProperty("aTuple/0", context); - -/*********************************************************************************************************************** - * Check model.getOriginalProperty - **********************************************************************************************************************/ - -/** @expect ok */ anObject = model.getOriginalProperty("anObject", context); -/** @expect ok */ anArray = model.getOriginalProperty("anArray", context); -/** @expect ok */ aJsonSafeArray = model.getOriginalProperty("aJsonSafeArray", context); -/** @expect ok */ aJsonSafe = model.getOriginalProperty("aJsonSafeArray/0", context); -/** @expect ok */ aPlaceholder = model.getOriginalProperty("aPlaceholder", context); -/** @expect ok */ anArrayOfPlaceholders = model.getOriginalProperty("anArrayOfPlaceholders", context); -/** @expect ok */ anotherPlaceholder = model.getOriginalProperty("anArrayOfPlaceholders/0", context); -/** @expect ok */ aTuple = model.getOriginalProperty("aTuple", context); -/** @expect ok */ anElementInATuple = model.getOriginalProperty("aTuple/0", context); - -/** @expect ts2345 */ anything = model.getOriginalProperty("anObject/0", context); -/** @expect ts2345 */ anything = model.getOriginalProperty("doesNotExist", context); -/** @expect ts2345 */ anything = model.getOriginalProperty("anArray/0/doesNotExist", context); - -/** @expect ts2739 */ aPlaceholder = model.getOriginalProperty("anObject", context); -/** @expect ts2322 */ anArrayOfPlaceholders = model.getOriginalProperty("aJsonSafeArray", context); -/** @expect ts2322 */ anObject = model.getOriginalProperty("aJsonSafeArray/0", context); -/** @expect ts2322 */ aJsonSafe = model.getOriginalProperty("aPlaceholder", context); -/** @expect ts2322 */ aJsonSafe = model.getOriginalProperty("anArrayOfPlaceholders/0", context); -/** @expect ts2322 */ anElementInATuple = model.getOriginalProperty("aTuple", context); -/** @expect ts2322 */ anObject = model.getOriginalProperty("aTuple/0", context); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-interface.ts b/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-interface.ts index 54e3c69..40236f3 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-interface.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-interface.ts @@ -67,29 +67,3 @@ import { TypedJSONModel } from "../../model"; /** @expect ts2322 */ aJsonSafe = model.getProperty("anArrayOfPlaceholders/0", context); /** @expect ts2322 */ anElementInATuple = model.getProperty("aTuple", context); /** @expect ts2322 */ anObject = model.getProperty("aTuple/0", context); - -/*********************************************************************************************************************** - * Check model.getOriginalProperty - **********************************************************************************************************************/ - -/** @expect ok */ anObject = model.getOriginalProperty("anObject", context); -/** @expect ok */ anArray = model.getOriginalProperty("anArray", context); -/** @expect ok */ aJsonSafeArray = model.getOriginalProperty("aJsonSafeArray", context); -/** @expect ok */ aJsonSafe = model.getOriginalProperty("aJsonSafeArray/0", context); -/** @expect ok */ aPlaceholder = model.getOriginalProperty("aPlaceholder", context); -/** @expect ok */ anArrayOfPlaceholders = model.getOriginalProperty("anArrayOfPlaceholders", context); -/** @expect ok */ anotherPlaceholder = model.getOriginalProperty("anArrayOfPlaceholders/0", context); -/** @expect ok */ aTuple = model.getOriginalProperty("aTuple", context); -/** @expect ok */ anElementInATuple = model.getOriginalProperty("aTuple/0", context); - -/** @expect ts2345 */ anything = model.getOriginalProperty("anObject/0", context); -/** @expect ts2345 */ anything = model.getOriginalProperty("doesNotExist", context); -/** @expect ts2345 */ anything = model.getOriginalProperty("anArray/0/doesNotExist", context); - -/** @expect ts2739 */ aPlaceholder = model.getOriginalProperty("anObject", context); -/** @expect ts2322 */ anArrayOfPlaceholders = model.getOriginalProperty("aJsonSafeArray", context); -/** @expect ts2322 */ anObject = model.getOriginalProperty("aJsonSafeArray/0", context); -/** @expect ts2322 */ aJsonSafe = model.getOriginalProperty("aPlaceholder", context); -/** @expect ts2322 */ aJsonSafe = model.getOriginalProperty("anArrayOfPlaceholders/0", context); -/** @expect ts2322 */ anElementInATuple = model.getOriginalProperty("aTuple", context); -/** @expect ts2322 */ anObject = model.getOriginalProperty("aTuple/0", context); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-typeAlias.ts b/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-typeAlias.ts index 9caf05f..8b0dedc 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-typeAlias.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-typeAlias.ts @@ -69,29 +69,3 @@ model.getProperty("/root/aPlaceholder", context); /** @expect ts2322 */ aJsonSafe = model.getProperty("anArrayOfPlaceholders/0", context); /** @expect ts2322 */ anElementInATuple = model.getProperty("aTuple", context); /** @expect ts2322 */ anObject = model.getProperty("aTuple/0", context); - -/*********************************************************************************************************************** - * Check model.getOriginalProperty - **********************************************************************************************************************/ - -/** @expect ok */ anObject = model.getOriginalProperty("anObject", context); -/** @expect ok */ anArray = model.getOriginalProperty("anArray", context); -/** @expect ok */ aJsonSafeArray = model.getOriginalProperty("aJsonSafeArray", context); -/** @expect ok */ aJsonSafe = model.getOriginalProperty("aJsonSafeArray/0", context); -/** @expect ok */ aPlaceholder = model.getOriginalProperty("aPlaceholder", context); -/** @expect ok */ anArrayOfPlaceholders = model.getOriginalProperty("anArrayOfPlaceholders", context); -/** @expect ok */ anotherPlaceholder = model.getOriginalProperty("anArrayOfPlaceholders/0", context); -/** @expect ok */ aTuple = model.getOriginalProperty("aTuple", context); -/** @expect ok */ anElementInATuple = model.getOriginalProperty("aTuple/0", context); - -/** @expect ts2345 */ anything = model.getOriginalProperty("anObject/0", context); -/** @expect ts2345 */ anything = model.getOriginalProperty("doesNotExist", context); -/** @expect ts2345 */ anything = model.getOriginalProperty("anArray/0/doesNotExist", context); - -/** @expect ts2739 */ aPlaceholder = model.getOriginalProperty("anObject", context); -/** @expect ts2322 */ anArrayOfPlaceholders = model.getOriginalProperty("aJsonSafeArray", context); -/** @expect ts2322 */ anObject = model.getOriginalProperty("aJsonSafeArray/0", context); -/** @expect ts2322 */ aJsonSafe = model.getOriginalProperty("aPlaceholder", context); -/** @expect ts2322 */ aJsonSafe = model.getOriginalProperty("anArrayOfPlaceholders/0", context); -/** @expect ts2322 */ anElementInATuple = model.getOriginalProperty("aTuple", context); -/** @expect ts2322 */ anObject = model.getOriginalProperty("aTuple/0", context); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/relative-primitive-inference.ts b/test-packages/typed-json-model/webapp/model/test/cases/relative-primitive-inference.ts index 8f6ac49..58ea435 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/relative-primitive-inference.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/relative-primitive-inference.ts @@ -53,24 +53,3 @@ let aSymbol: symbol = Symbol("test"); // value is a symbol -> not JSON serializable! /** @expect ts2322 */ aSymbol = model.getProperty("aSymbol", context); - -/*********************************************************************************************************************** - * Check model.getOriginalProperty - **********************************************************************************************************************/ - -/** @expect ok */ aString = model.getOriginalProperty("aString", context); -/** @expect ok */ aNumber = model.getOriginalProperty("aNumber", context); -/** @expect ok */ aBoolean = model.getOriginalProperty("aBoolean", context); -/** @expect ok */ aNull = model.getOriginalProperty("aNull", context); -/** @expect ok */ anUndefined = model.getOriginalProperty("anUndefined", context); - -/** @expect ts2345 */ const test1 = model.getOriginalProperty("doesNotExist", context); - -/** @expect ts2322 */ aString = model.getOriginalProperty("aNumber", context); -/** @expect ts2322 */ aNumber = model.getOriginalProperty("aString", context); -/** @expect ts2322 */ aString = model.getOriginalProperty("aBoolean", context); -/** @expect ts2322 */ aNull = model.getOriginalProperty("anUndefined", context); -/** @expect ts2322 */ anUndefined = model.getOriginalProperty("aNull", context); - -// value is a symbol -> not JSON serializable! -/** @expect ts2322 */ aSymbol = model.getOriginalProperty("aSymbol", context); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/relative-primitive-interface.ts b/test-packages/typed-json-model/webapp/model/test/cases/relative-primitive-interface.ts index a5fd363..b5675f6 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/relative-primitive-interface.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/relative-primitive-interface.ts @@ -53,24 +53,3 @@ let aSymbol: symbol = Symbol("test"); // value is a symbol -> not JSON serializable! /** @expect ts2322 */ aSymbol = model.getProperty("aSymbol", context); - -/*********************************************************************************************************************** - * Check model.getOriginalProperty - **********************************************************************************************************************/ - -/** @expect ok */ aString = model.getOriginalProperty("aString", context); -/** @expect ok */ aNumber = model.getOriginalProperty("aNumber", context); -/** @expect ok */ aBoolean = model.getOriginalProperty("aBoolean", context); -/** @expect ok */ aNull = model.getOriginalProperty("aNull", context); -/** @expect ok */ anUndefined = model.getOriginalProperty("anUndefined", context); - -/** @expect ts2345 */ const test1 = model.getOriginalProperty("doesNotExist", context); - -/** @expect ts2322 */ aString = model.getOriginalProperty("aNumber", context); -/** @expect ts2322 */ aNumber = model.getOriginalProperty("aString", context); -/** @expect ts2322 */ aString = model.getOriginalProperty("aBoolean", context); -/** @expect ts2322 */ aNull = model.getOriginalProperty("anUndefined", context); -/** @expect ts2322 */ anUndefined = model.getOriginalProperty("aNull", context); - -// value is a symbol -> not JSON serializable! -/** @expect ts2322 */ aSymbol = model.getOriginalProperty("aSymbol", context); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/relative-primitive-typeAlias.ts b/test-packages/typed-json-model/webapp/model/test/cases/relative-primitive-typeAlias.ts index 5c4bcfb..280b851 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/relative-primitive-typeAlias.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/relative-primitive-typeAlias.ts @@ -53,24 +53,3 @@ let aSymbol: symbol = Symbol("test"); // value is a symbol -> not JSON serializable! /** @expect ts2322 */ aSymbol = model.getProperty("aSymbol", context); - -/*********************************************************************************************************************** - * Check model.getOriginalProperty - **********************************************************************************************************************/ - -/** @expect ok */ aString = model.getOriginalProperty("aString", context); -/** @expect ok */ aNumber = model.getOriginalProperty("aNumber", context); -/** @expect ok */ aBoolean = model.getOriginalProperty("aBoolean", context); -/** @expect ok */ aNull = model.getOriginalProperty("aNull", context); -/** @expect ok */ anUndefined = model.getOriginalProperty("anUndefined", context); - -/** @expect ts2345 */ const test1 = model.getOriginalProperty("doesNotExist", context); - -/** @expect ts2322 */ aString = model.getOriginalProperty("aNumber", context); -/** @expect ts2322 */ aNumber = model.getOriginalProperty("aString", context); -/** @expect ts2322 */ aString = model.getOriginalProperty("aBoolean", context); -/** @expect ts2322 */ aNull = model.getOriginalProperty("anUndefined", context); -/** @expect ts2322 */ anUndefined = model.getOriginalProperty("aNull", context); - -// value is a symbol -> not JSON serializable! -/** @expect ts2322 */ aSymbol = model.getOriginalProperty("aSymbol", context); From cd39e4ab5fe2b1b6495dd5659ce2d07cfb3e19fe Mon Sep 17 00:00:00 2001 From: viktorsperling Date: Wed, 28 Jan 2026 16:04:14 +0100 Subject: [PATCH 2/7] feat(dts-generator): add bindList declarations and tests to TypedJSONModel --- .../typed-json-model/webapp/model/model.ts | 7 +++++++ .../model/test/cases/absolute-complex-inference.ts | 14 ++++++++++++++ .../model/test/cases/absolute-complex-interface.ts | 14 ++++++++++++++ .../model/test/cases/absolute-complex-typeAlias.ts | 14 ++++++++++++++ .../typed-json-model/webapp/model/test/input.ts | 9 +++++++++ .../typed-json-model/webapp/model/typing.ts | 13 +++++++++++++ 6 files changed, 71 insertions(+) diff --git a/test-packages/typed-json-model/webapp/model/model.ts b/test-packages/typed-json-model/webapp/model/model.ts index a3b70ad..35d5f02 100644 --- a/test-packages/typed-json-model/webapp/model/model.ts +++ b/test-packages/typed-json-model/webapp/model/model.ts @@ -1,7 +1,10 @@ import Context from "sap/ui/model/Context"; import JSONModel from "sap/ui/model/json/JSONModel"; +import JSONListBinding from "sap/ui/model/json/JSONListBinding"; import { AbsoluteBindingPath, + AbsoluteListBindingPath, + FromArrayWithSubPath, PropertyByAbsoluteBindingPath, PropertyByRelativeBindingPath, RelativeBindingPath, @@ -57,6 +60,10 @@ export class TypedJSONModel extends JSONModel { | PropertyByRelativeBindingPath; } + bindList>(sPath: Path): JSONListBinding { + return super.bindList(sPath); + } + setData(oData: Data, bMerge?: boolean): void { super.setData(oData, bMerge); } diff --git a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-inference.ts b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-inference.ts index 6a37cff..97f7d0e 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-inference.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-inference.ts @@ -10,6 +10,7 @@ */ import { JSONSafe, objectLikeByInference, Placeholder } from "../input"; +import JSONListBinding from "sap/ui/model/json/JSONListBinding"; import { TypedJSONModel } from "../../model"; @@ -76,3 +77,16 @@ import { TypedJSONModel } from "../../model"; /** @expect ts2740 */ const dataB: Array = model.getData(); /** @expect ts2345 */ model.setData(dataB); + +/*********************************************************************************************************************** + * Check model.bindList + **********************************************************************************************************************/ + +/** @expect ok */ let ListBinding: JSONListBinding = model.bindList("/anArray"); +/** @expect ok */ ListBinding = model.bindList("/anArrayOfArrays/0"); +/** @expect ok */ ListBinding = model.bindList("/anObjectWithArray/anArray"); + +/** @expect ts2345 */ ListBinding = model.bindList("/aJsonSafeArray/0"); +/** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfArrays/0/0"); +/** @expect ts2345 */ ListBinding = model.bindList("/anObjectWithArray/anArray/0"); +/** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfObjects/0"); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-interface.ts b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-interface.ts index 142b3b8..7459289 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-interface.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-interface.ts @@ -10,6 +10,7 @@ */ import { IObjectLike, JSONSafe, objectLikeByInterface, Placeholder, TObjectLike } from "../input"; +import JSONListBinding from "sap/ui/model/json/JSONListBinding"; import { TypedJSONModel } from "../../model"; @@ -81,3 +82,16 @@ import { TypedJSONModel } from "../../model"; /** @expect ts2740 */ const dataC: Array = model.getData(); /** @expect ts2345 */ model.setData(dataC); + +/*********************************************************************************************************************** + * Check model.bindList + **********************************************************************************************************************/ + +/** @expect ok */ let ListBinding: JSONListBinding = model.bindList("/anArray"); +/** @expect ok */ ListBinding = model.bindList("/anArrayOfArrays/0"); +/** @expect ok */ ListBinding = model.bindList("/anObjectWithArray/anArray"); + +/** @expect ts2345 */ ListBinding = model.bindList("/aJsonSafeArray/0"); +/** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfArrays/0/0"); +/** @expect ts2345 */ ListBinding = model.bindList("/anObjectWithArray/anArray/0"); +/** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfPlaceholders/0"); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-typeAlias.ts b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-typeAlias.ts index ab91bbc..06b7261 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-typeAlias.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-typeAlias.ts @@ -10,6 +10,7 @@ */ import { IObjectLike, JSONSafe, objectLikeByTypeAlias, Placeholder, TObjectLike } from "../input"; +import JSONListBinding from "sap/ui/model/json/JSONListBinding"; import { TypedJSONModel } from "../../model"; @@ -81,3 +82,16 @@ import { TypedJSONModel } from "../../model"; /** @expect ts2740 */ const dataC: Array = model.getData(); /** @expect ts2345 */ model.setData(dataC); + +/*********************************************************************************************************************** + * Check model.bindList + **********************************************************************************************************************/ + +/** @expect ok */ let ListBinding: JSONListBinding = model.bindList("/anArray"); +/** @expect ok */ ListBinding = model.bindList("/anArrayOfArrays/0"); +/** @expect ok */ ListBinding = model.bindList("/anObjectWithArray/anArray"); + +/** @expect ts2345 */ ListBinding = model.bindList("/aJsonSafeArray/0"); +/** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfArrays/0/0"); +/** @expect ts2345 */ ListBinding = model.bindList("/anObjectWithArray/anArray/0"); +/** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfPlaceholders/0"); diff --git a/test-packages/typed-json-model/webapp/model/test/input.ts b/test-packages/typed-json-model/webapp/model/test/input.ts index a8286f6..b2b8839 100644 --- a/test-packages/typed-json-model/webapp/model/test/input.ts +++ b/test-packages/typed-json-model/webapp/model/test/input.ts @@ -58,7 +58,9 @@ export interface IPrimitives { export type TObjectLike = { anObject: object; anArray: Array; + anArrayOfArrays: Array>; aJsonSafeArray: Array; + anObjectWithArray: { anArray: Array }; anArrayOfPlaceholders: Array; aPlaceholder: Placeholder; aTuple: [string, number]; @@ -71,7 +73,9 @@ export type TObjectLike = { export interface IObjectLike { anObject: object; anArray: Array; + anArrayOfArrays: Array>; aJsonSafeArray: Array; + anObjectWithArray: { anArray: Array }; anArrayOfPlaceholders: Array; aPlaceholder: Placeholder; aTuple: [string, number]; @@ -149,8 +153,13 @@ export const objectLikeByInterface: IObjectLike = { export const objectLikeByInference = { anObject: {}, anArray: [], + anArrayOfArrays: [ + ["string", 1], + [true, false], + ], aJsonSafeArray: ["string", 1, true], anArrayOfObjects: [{ aNumber: 1 }], + anObjectWithArray: { anArray: ["string"] }, anArrayOfPlaceholders: [new Placeholder()], aPlaceholder: new Placeholder(), aTuple: ["string", 1], diff --git a/test-packages/typed-json-model/webapp/model/typing.ts b/test-packages/typed-json-model/webapp/model/typing.ts index ba6d7f9..623ac28 100644 --- a/test-packages/typed-json-model/webapp/model/typing.ts +++ b/test-packages/typed-json-model/webapp/model/typing.ts @@ -28,6 +28,19 @@ export type AbsoluteBindingPath = : // if T is not of type object: never; +/** + * Valid absolute binding in a JSONModel with the underlying type `Type`. + * Counterpart to {@link PropertyByAbsoluteBindingPath} + * @example + * type Person = { name: string, id: number }; + * type PathInPerson = PathInJSONModel; // "/name" | "/id" + * let path: PathInPerson = "/name"; // ok + * path = "/firstName"; // error + */ +export type AbsoluteListBindingPath = { + [Path in AbsoluteBindingPath]: PropertyByAbsoluteBindingPath extends Array ? Path : never; +}[AbsoluteBindingPath]; + /** * Valid relative binding path in a JSONModel. * The root of the path is defined by the given root string. From 56d6d990bc510e45d3bb17cdc78ac649959ced12 Mon Sep 17 00:00:00 2001 From: viktorsperling Date: Wed, 28 Jan 2026 17:24:52 +0100 Subject: [PATCH 3/7] fix(dts-generator): fix ESLint errors --- test-packages/typed-json-model/webapp/model/model.ts | 1 - test-packages/typed-json-model/webapp/model/typing.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/test-packages/typed-json-model/webapp/model/model.ts b/test-packages/typed-json-model/webapp/model/model.ts index 35d5f02..9fd6c6d 100644 --- a/test-packages/typed-json-model/webapp/model/model.ts +++ b/test-packages/typed-json-model/webapp/model/model.ts @@ -4,7 +4,6 @@ import JSONListBinding from "sap/ui/model/json/JSONListBinding"; import { AbsoluteBindingPath, AbsoluteListBindingPath, - FromArrayWithSubPath, PropertyByAbsoluteBindingPath, PropertyByRelativeBindingPath, RelativeBindingPath, diff --git a/test-packages/typed-json-model/webapp/model/typing.ts b/test-packages/typed-json-model/webapp/model/typing.ts index 623ac28..697e818 100644 --- a/test-packages/typed-json-model/webapp/model/typing.ts +++ b/test-packages/typed-json-model/webapp/model/typing.ts @@ -38,7 +38,7 @@ export type AbsoluteBindingPath = * path = "/firstName"; // error */ export type AbsoluteListBindingPath = { - [Path in AbsoluteBindingPath]: PropertyByAbsoluteBindingPath extends Array ? Path : never; + [Path in AbsoluteBindingPath]: PropertyByAbsoluteBindingPath extends Array ? Path : never; }[AbsoluteBindingPath]; /** From aa50371ee8cbfb63d1f2ae752b971ae5f7d383a9 Mon Sep 17 00:00:00 2001 From: viktorsperling Date: Wed, 28 Jan 2026 17:58:14 +0100 Subject: [PATCH 4/7] fix(dts-generator): fix failing tests --- test-packages/typed-json-model/webapp/model/test/input.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test-packages/typed-json-model/webapp/model/test/input.ts b/test-packages/typed-json-model/webapp/model/test/input.ts index b2b8839..bb527f5 100644 --- a/test-packages/typed-json-model/webapp/model/test/input.ts +++ b/test-packages/typed-json-model/webapp/model/test/input.ts @@ -58,9 +58,9 @@ export interface IPrimitives { export type TObjectLike = { anObject: object; anArray: Array; - anArrayOfArrays: Array>; + anArrayOfArrays: Array>; aJsonSafeArray: Array; - anObjectWithArray: { anArray: Array }; + anObjectWithArray: { anArray: Array }; anArrayOfPlaceholders: Array; aPlaceholder: Placeholder; aTuple: [string, number]; From ce06c950f2d6ea84f17e65a0006bfd6530f1f031 Mon Sep 17 00:00:00 2001 From: viktorsperling Date: Thu, 29 Jan 2026 15:30:30 +0100 Subject: [PATCH 5/7] feat(dts-generator): add typing for relative binding paths to bindList --- .../typed-json-model/webapp/model/model.ts | 33 +++++++++++++++++-- .../test/cases/absolute-complex-inference.ts | 6 ++++ .../test/cases/absolute-complex-interface.ts | 6 ++++ .../test/cases/absolute-complex-typeAlias.ts | 6 ++++ .../test/cases/relative-complex-inference.ts | 20 +++++++++++ .../test/cases/relative-complex-interface.ts | 20 +++++++++++ .../test/cases/relative-complex-typeAlias.ts | 20 +++++++++++ .../webapp/model/test/input.ts | 10 ++++++ .../typed-json-model/webapp/model/typing.ts | 27 +++++++++++---- 9 files changed, 140 insertions(+), 8 deletions(-) diff --git a/test-packages/typed-json-model/webapp/model/model.ts b/test-packages/typed-json-model/webapp/model/model.ts index 9fd6c6d..a33f681 100644 --- a/test-packages/typed-json-model/webapp/model/model.ts +++ b/test-packages/typed-json-model/webapp/model/model.ts @@ -1,12 +1,15 @@ import Context from "sap/ui/model/Context"; import JSONModel from "sap/ui/model/json/JSONModel"; import JSONListBinding from "sap/ui/model/json/JSONListBinding"; +import Sorter from "sap/ui/model/Sorter"; +import Filter from "sap/ui/model/Filter"; import { AbsoluteBindingPath, AbsoluteListBindingPath, PropertyByAbsoluteBindingPath, PropertyByRelativeBindingPath, RelativeBindingPath, + RelativeListBindingPath, } from "./typing"; export class TypedJSONContext> extends Context { @@ -59,8 +62,34 @@ export class TypedJSONModel extends JSONModel { | PropertyByRelativeBindingPath; } - bindList>(sPath: Path): JSONListBinding { - return super.bindList(sPath); + // Overload for absolute paths + bindList>( + sPath: Path, + oContext?: undefined, + aSorters?: Sorter | Sorter[], + aFilters?: Filter | Filter[], + mParameters?: object, + ): JSONListBinding; + // Overload for relative paths + bindList, Path extends RelativeListBindingPath>( + sPath: Path, + oContext: TypedJSONContext, + aSorters?: Sorter | Sorter[], + aFilters?: Filter | Filter[], + mParameters?: object, + ): JSONListBinding; + // Implementation + bindList< + Path extends AbsoluteListBindingPath | RelativeListBindingPath, + Root extends AbsoluteBindingPath, + >( + sPath: Path, + oContext?: TypedJSONContext, + aSorters?: Sorter | Sorter[], + aFilters?: Filter | Filter[], + mParameters?: object, + ): JSONListBinding { + return super.bindList(sPath, oContext, aSorters, aFilters, mParameters); } setData(oData: Data, bMerge?: boolean): void { diff --git a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-inference.ts b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-inference.ts index 97f7d0e..956282e 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-inference.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-inference.ts @@ -86,7 +86,13 @@ import { TypedJSONModel } from "../../model"; /** @expect ok */ ListBinding = model.bindList("/anArrayOfArrays/0"); /** @expect ok */ ListBinding = model.bindList("/anObjectWithArray/anArray"); +// incorrect binding paths /** @expect ts2345 */ ListBinding = model.bindList("/aJsonSafeArray/0"); /** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfArrays/0/0"); /** @expect ts2345 */ ListBinding = model.bindList("/anObjectWithArray/anArray/0"); +/** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfPlaceholders/0"); /** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfObjects/0"); + +// bindList always returns a JSONListBinding and cannot be assigned to other types +/** @expect ts2739 */ aPlaceholder = model.bindList("/anArray"); +/** @expect ts2322 */ aJsonSafe = model.bindList("/anArray"); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-interface.ts b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-interface.ts index 7459289..7f0fb33 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-interface.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-interface.ts @@ -91,7 +91,13 @@ import { TypedJSONModel } from "../../model"; /** @expect ok */ ListBinding = model.bindList("/anArrayOfArrays/0"); /** @expect ok */ ListBinding = model.bindList("/anObjectWithArray/anArray"); +// incorrect binding paths /** @expect ts2345 */ ListBinding = model.bindList("/aJsonSafeArray/0"); /** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfArrays/0/0"); /** @expect ts2345 */ ListBinding = model.bindList("/anObjectWithArray/anArray/0"); /** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfPlaceholders/0"); +/** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfObjects/0"); + +// bindList always returns a JSONListBinding and cannot be assigned to other types +/** @expect ts2739 */ aPlaceholder = model.bindList("/anArray"); +/** @expect ts2322 */ aJsonSafe = model.bindList("/anArray"); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-typeAlias.ts b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-typeAlias.ts index 06b7261..1fa06d6 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-typeAlias.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-typeAlias.ts @@ -91,7 +91,13 @@ import { TypedJSONModel } from "../../model"; /** @expect ok */ ListBinding = model.bindList("/anArrayOfArrays/0"); /** @expect ok */ ListBinding = model.bindList("/anObjectWithArray/anArray"); +// incorrect binding paths /** @expect ts2345 */ ListBinding = model.bindList("/aJsonSafeArray/0"); /** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfArrays/0/0"); /** @expect ts2345 */ ListBinding = model.bindList("/anObjectWithArray/anArray/0"); /** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfPlaceholders/0"); +/** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfObjects/0"); + +// bindList always returns a JSONListBinding and cannot be assigned to other types +/** @expect ts2739 */ aPlaceholder = model.bindList("/anArray"); +/** @expect ts2322 */ aJsonSafe = model.bindList("/anArray"); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-inference.ts b/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-inference.ts index b730283..188ac7b 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-inference.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-inference.ts @@ -10,6 +10,7 @@ */ import { JSONSafe, objectLikeByInference, Placeholder } from "../input"; +import JSONListBinding from "sap/ui/model/json/JSONListBinding"; import { TypedJSONModel } from "../../model"; @@ -67,3 +68,22 @@ import { TypedJSONModel } from "../../model"; /** @expect ts2322 */ aJsonSafe = model.getProperty("anArrayOfPlaceholders/0", context); /** @expect ts2322 */ anElementInATuple = model.getProperty("aTuple", context); /** @expect ts2322 */ anObject = model.getProperty("aTuple/0", context); + +/*********************************************************************************************************************** + * Check model.bindList + **********************************************************************************************************************/ + +/** @expect ok */ let ListBinding: JSONListBinding = model.bindList("anArray", context); +/** @expect ok */ ListBinding = model.bindList("anArrayOfArrays/0", context); +/** @expect ok */ ListBinding = model.bindList("anObjectWithArray/anArray", context); + +// incorrect binding paths +/** @expect ts2769 */ ListBinding = model.bindList("aJsonSafeArray/0", context); +/** @expect ts2769 */ ListBinding = model.bindList("anArrayOfArrays/0/0", context); +/** @expect ts2769 */ ListBinding = model.bindList("anObjectWithArray/anArray/0", context); +/** @expect ts2769 */ ListBinding = model.bindList("anArrayOfPlaceholders/0", context); +/** @expect ts2769 */ ListBinding = model.bindList("anArrayOfObjects/0", context); + +// bindList always returns a JSONListBinding and cannot be assigned to other types +/** @expect ts2739 */ aPlaceholder = model.bindList("anArray", context); +/** @expect ts2322 */ aJsonSafe = model.bindList("anArray", context); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-interface.ts b/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-interface.ts index 40236f3..413187f 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-interface.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-interface.ts @@ -10,6 +10,7 @@ */ import { JSONSafe, objectLikeByInterface, Placeholder } from "../input"; +import JSONListBinding from "sap/ui/model/json/JSONListBinding"; import { TypedJSONModel } from "../../model"; @@ -67,3 +68,22 @@ import { TypedJSONModel } from "../../model"; /** @expect ts2322 */ aJsonSafe = model.getProperty("anArrayOfPlaceholders/0", context); /** @expect ts2322 */ anElementInATuple = model.getProperty("aTuple", context); /** @expect ts2322 */ anObject = model.getProperty("aTuple/0", context); + +/*********************************************************************************************************************** + * Check model.bindList + **********************************************************************************************************************/ + +/** @expect ok */ let ListBinding: JSONListBinding = model.bindList("anArray", context); +/** @expect ok */ ListBinding = model.bindList("anArrayOfArrays/0", context); +/** @expect ok */ ListBinding = model.bindList("anObjectWithArray/anArray", context); + +// incorrect binding paths +/** @expect ts2769 */ ListBinding = model.bindList("aJsonSafeArray/0", context); +/** @expect ts2769 */ ListBinding = model.bindList("anArrayOfArrays/0/0", context); +/** @expect ts2769 */ ListBinding = model.bindList("anObjectWithArray/anArray/0", context); +/** @expect ts2769 */ ListBinding = model.bindList("anArrayOfPlaceholders/0", context); +/** @expect ts2769 */ ListBinding = model.bindList("anArrayOfObjects/0", context); + +// bindList always returns a JSONListBinding and cannot be assigned to other types +/** @expect ts2739 */ aPlaceholder = model.bindList("anArray", context); +/** @expect ts2322 */ aJsonSafe = model.bindList("anArray", context); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-typeAlias.ts b/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-typeAlias.ts index 8b0dedc..59e2a11 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-typeAlias.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-typeAlias.ts @@ -10,6 +10,7 @@ */ import { JSONSafe, objectLikeByTypeAlias, Placeholder } from "../input"; +import JSONListBinding from "sap/ui/model/json/JSONListBinding"; import { TypedJSONModel } from "../../model"; @@ -69,3 +70,22 @@ model.getProperty("/root/aPlaceholder", context); /** @expect ts2322 */ aJsonSafe = model.getProperty("anArrayOfPlaceholders/0", context); /** @expect ts2322 */ anElementInATuple = model.getProperty("aTuple", context); /** @expect ts2322 */ anObject = model.getProperty("aTuple/0", context); + +/*********************************************************************************************************************** + * Check model.bindList + **********************************************************************************************************************/ + +/** @expect ok */ let ListBinding: JSONListBinding = model.bindList("anArray", context); +/** @expect ok */ ListBinding = model.bindList("anArrayOfArrays/0", context); +/** @expect ok */ ListBinding = model.bindList("anObjectWithArray/anArray", context); + +// incorrect binding paths +/** @expect ts2769 */ ListBinding = model.bindList("aJsonSafeArray/0", context); +/** @expect ts2769 */ ListBinding = model.bindList("anArrayOfArrays/0/0", context); +/** @expect ts2769 */ ListBinding = model.bindList("anObjectWithArray/anArray/0", context); +/** @expect ts2769 */ ListBinding = model.bindList("anArrayOfPlaceholders/0", context); +/** @expect ts2769 */ ListBinding = model.bindList("anArrayOfObjects/0", context); + +// bindList always returns a JSONListBinding and cannot be assigned to other types +/** @expect ts2739 */ aPlaceholder = model.bindList("anArray", context); +/** @expect ts2322 */ aJsonSafe = model.bindList("anArray", context); diff --git a/test-packages/typed-json-model/webapp/model/test/input.ts b/test-packages/typed-json-model/webapp/model/test/input.ts index bb527f5..aac9fe7 100644 --- a/test-packages/typed-json-model/webapp/model/test/input.ts +++ b/test-packages/typed-json-model/webapp/model/test/input.ts @@ -127,8 +127,13 @@ export const primitivesByInference = { export const objectLikeByTypeAlias: TObjectLike = { anObject: {}, anArray: [], + anArrayOfArrays: [ + ["string", 1], + [true, false], + ], aJsonSafeArray: ["string", 1, true], anArrayOfPlaceholders: [new Placeholder()], + anObjectWithArray: { anArray: ["string"] }, aPlaceholder: new Placeholder(), aTuple: ["string", 1], }; @@ -140,8 +145,13 @@ export const objectLikeByTypeAlias: TObjectLike = { export const objectLikeByInterface: IObjectLike = { anObject: {}, anArray: [], + anArrayOfArrays: [ + ["string", 1], + [true, false], + ], aJsonSafeArray: ["string", 1, true], anArrayOfPlaceholders: [new Placeholder()], + anObjectWithArray: { anArray: ["string"] }, aPlaceholder: new Placeholder(), aTuple: ["string", 1], }; diff --git a/test-packages/typed-json-model/webapp/model/typing.ts b/test-packages/typed-json-model/webapp/model/typing.ts index 697e818..6613c88 100644 --- a/test-packages/typed-json-model/webapp/model/typing.ts +++ b/test-packages/typed-json-model/webapp/model/typing.ts @@ -29,13 +29,14 @@ export type AbsoluteBindingPath = never; /** - * Valid absolute binding in a JSONModel with the underlying type `Type`. - * Counterpart to {@link PropertyByAbsoluteBindingPath} + * Valid absolute binding path for underlying `Array` types. + * * @example - * type Person = { name: string, id: number }; - * type PathInPerson = PathInJSONModel; // "/name" | "/id" - * let path: PathInPerson = "/name"; // ok - * path = "/firstName"; // error + * type SalesOrder = { id: string, items: string[] }; + * type PathInObject = PathInJSONModel; // "/id" | "/items" + * let path: PathInObject = "/items"; // ok + * path = "/id"; // error + * path = "/items/0"; // error, since an element in the array is a string */ export type AbsoluteListBindingPath = { [Path in AbsoluteBindingPath]: PropertyByAbsoluteBindingPath extends Array ? Path : never; @@ -52,6 +53,20 @@ export type AbsoluteListBindingPath = { export type RelativeBindingPath> = AbsoluteBindingPath> extends `/${infer Rest}` ? Rest : never; +/** + * Valid relative binding path for underlying `Array` types. + * The root of the path is defined by the given root string. + * + * @example + * type SalesOrder = { buyer: { id: string, items: string[] } }; + * type PathRelativeToSalesOrder = RelativeListBindingPath; // "id" | "items" + */ +export type RelativeListBindingPath> = { + [Path in RelativeBindingPath]: PropertyByRelativeBindingPath extends Array + ? Path + : never; +}[RelativeBindingPath]; + /** * The type of a property in a JSONModel identified by the given path. * Counterpart to {@link AbsoluteBindingPath}. From 3471c04746d91270b8799fa86ba0d7371505acf5 Mon Sep 17 00:00:00 2001 From: viktorsperling Date: Mon, 2 Feb 2026 08:56:16 +0100 Subject: [PATCH 6/7] chore(dts-generator): review comments --- .../typed-json-model/webapp/model/model.ts | 2 +- .../test/cases/absolute-complex-inference.ts | 16 ++++++++-------- .../test/cases/absolute-complex-interface.ts | 16 ++++++++-------- .../test/cases/absolute-complex-typeAlias.ts | 16 ++++++++-------- .../test/cases/relative-complex-inference.ts | 16 ++++++++-------- .../test/cases/relative-complex-interface.ts | 16 ++++++++-------- .../test/cases/relative-complex-typeAlias.ts | 16 ++++++++-------- 7 files changed, 49 insertions(+), 49 deletions(-) diff --git a/test-packages/typed-json-model/webapp/model/model.ts b/test-packages/typed-json-model/webapp/model/model.ts index a33f681..b72443d 100644 --- a/test-packages/typed-json-model/webapp/model/model.ts +++ b/test-packages/typed-json-model/webapp/model/model.ts @@ -71,7 +71,7 @@ export class TypedJSONModel extends JSONModel { mParameters?: object, ): JSONListBinding; // Overload for relative paths - bindList, Path extends RelativeListBindingPath>( + bindList, Root extends AbsoluteBindingPath>( sPath: Path, oContext: TypedJSONContext, aSorters?: Sorter | Sorter[], diff --git a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-inference.ts b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-inference.ts index 956282e..57d0a22 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-inference.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-inference.ts @@ -82,16 +82,16 @@ import { TypedJSONModel } from "../../model"; * Check model.bindList **********************************************************************************************************************/ -/** @expect ok */ let ListBinding: JSONListBinding = model.bindList("/anArray"); -/** @expect ok */ ListBinding = model.bindList("/anArrayOfArrays/0"); -/** @expect ok */ ListBinding = model.bindList("/anObjectWithArray/anArray"); +/** @expect ok */ let listBinding: JSONListBinding = model.bindList("/anArray"); +/** @expect ok */ listBinding = model.bindList("/anArrayOfArrays/0"); +/** @expect ok */ listBinding = model.bindList("/anObjectWithArray/anArray"); // incorrect binding paths -/** @expect ts2345 */ ListBinding = model.bindList("/aJsonSafeArray/0"); -/** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfArrays/0/0"); -/** @expect ts2345 */ ListBinding = model.bindList("/anObjectWithArray/anArray/0"); -/** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfPlaceholders/0"); -/** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfObjects/0"); +/** @expect ts2345 */ listBinding = model.bindList("/aJsonSafeArray/0"); +/** @expect ts2345 */ listBinding = model.bindList("/anArrayOfArrays/0/0"); +/** @expect ts2345 */ listBinding = model.bindList("/anObjectWithArray/anArray/0"); +/** @expect ts2345 */ listBinding = model.bindList("/anArrayOfPlaceholders/0"); +/** @expect ts2345 */ listBinding = model.bindList("/anArrayOfObjects/0"); // bindList always returns a JSONListBinding and cannot be assigned to other types /** @expect ts2739 */ aPlaceholder = model.bindList("/anArray"); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-interface.ts b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-interface.ts index 7f0fb33..4162574 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-interface.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-interface.ts @@ -87,16 +87,16 @@ import { TypedJSONModel } from "../../model"; * Check model.bindList **********************************************************************************************************************/ -/** @expect ok */ let ListBinding: JSONListBinding = model.bindList("/anArray"); -/** @expect ok */ ListBinding = model.bindList("/anArrayOfArrays/0"); -/** @expect ok */ ListBinding = model.bindList("/anObjectWithArray/anArray"); +/** @expect ok */ let listBinding: JSONListBinding = model.bindList("/anArray"); +/** @expect ok */ listBinding = model.bindList("/anArrayOfArrays/0"); +/** @expect ok */ listBinding = model.bindList("/anObjectWithArray/anArray"); // incorrect binding paths -/** @expect ts2345 */ ListBinding = model.bindList("/aJsonSafeArray/0"); -/** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfArrays/0/0"); -/** @expect ts2345 */ ListBinding = model.bindList("/anObjectWithArray/anArray/0"); -/** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfPlaceholders/0"); -/** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfObjects/0"); +/** @expect ts2345 */ listBinding = model.bindList("/aJsonSafeArray/0"); +/** @expect ts2345 */ listBinding = model.bindList("/anArrayOfArrays/0/0"); +/** @expect ts2345 */ listBinding = model.bindList("/anObjectWithArray/anArray/0"); +/** @expect ts2345 */ listBinding = model.bindList("/anArrayOfPlaceholders/0"); +/** @expect ts2345 */ listBinding = model.bindList("/anArrayOfObjects/0"); // bindList always returns a JSONListBinding and cannot be assigned to other types /** @expect ts2739 */ aPlaceholder = model.bindList("/anArray"); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-typeAlias.ts b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-typeAlias.ts index 1fa06d6..41c7f2d 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-typeAlias.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/absolute-complex-typeAlias.ts @@ -87,16 +87,16 @@ import { TypedJSONModel } from "../../model"; * Check model.bindList **********************************************************************************************************************/ -/** @expect ok */ let ListBinding: JSONListBinding = model.bindList("/anArray"); -/** @expect ok */ ListBinding = model.bindList("/anArrayOfArrays/0"); -/** @expect ok */ ListBinding = model.bindList("/anObjectWithArray/anArray"); +/** @expect ok */ let listBinding: JSONListBinding = model.bindList("/anArray"); +/** @expect ok */ listBinding = model.bindList("/anArrayOfArrays/0"); +/** @expect ok */ listBinding = model.bindList("/anObjectWithArray/anArray"); // incorrect binding paths -/** @expect ts2345 */ ListBinding = model.bindList("/aJsonSafeArray/0"); -/** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfArrays/0/0"); -/** @expect ts2345 */ ListBinding = model.bindList("/anObjectWithArray/anArray/0"); -/** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfPlaceholders/0"); -/** @expect ts2345 */ ListBinding = model.bindList("/anArrayOfObjects/0"); +/** @expect ts2345 */ listBinding = model.bindList("/aJsonSafeArray/0"); +/** @expect ts2345 */ listBinding = model.bindList("/anArrayOfArrays/0/0"); +/** @expect ts2345 */ listBinding = model.bindList("/anObjectWithArray/anArray/0"); +/** @expect ts2345 */ listBinding = model.bindList("/anArrayOfPlaceholders/0"); +/** @expect ts2345 */ listBinding = model.bindList("/anArrayOfObjects/0"); // bindList always returns a JSONListBinding and cannot be assigned to other types /** @expect ts2739 */ aPlaceholder = model.bindList("/anArray"); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-inference.ts b/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-inference.ts index 188ac7b..eb30dc0 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-inference.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-inference.ts @@ -73,16 +73,16 @@ import { TypedJSONModel } from "../../model"; * Check model.bindList **********************************************************************************************************************/ -/** @expect ok */ let ListBinding: JSONListBinding = model.bindList("anArray", context); -/** @expect ok */ ListBinding = model.bindList("anArrayOfArrays/0", context); -/** @expect ok */ ListBinding = model.bindList("anObjectWithArray/anArray", context); +/** @expect ok */ let listBinding: JSONListBinding = model.bindList("anArray", context); +/** @expect ok */ listBinding = model.bindList("anArrayOfArrays/0", context); +/** @expect ok */ listBinding = model.bindList("anObjectWithArray/anArray", context); // incorrect binding paths -/** @expect ts2769 */ ListBinding = model.bindList("aJsonSafeArray/0", context); -/** @expect ts2769 */ ListBinding = model.bindList("anArrayOfArrays/0/0", context); -/** @expect ts2769 */ ListBinding = model.bindList("anObjectWithArray/anArray/0", context); -/** @expect ts2769 */ ListBinding = model.bindList("anArrayOfPlaceholders/0", context); -/** @expect ts2769 */ ListBinding = model.bindList("anArrayOfObjects/0", context); +/** @expect ts2769 */ listBinding = model.bindList("aJsonSafeArray/0", context); +/** @expect ts2769 */ listBinding = model.bindList("anArrayOfArrays/0/0", context); +/** @expect ts2769 */ listBinding = model.bindList("anObjectWithArray/anArray/0", context); +/** @expect ts2769 */ listBinding = model.bindList("anArrayOfPlaceholders/0", context); +/** @expect ts2769 */ listBinding = model.bindList("anArrayOfObjects/0", context); // bindList always returns a JSONListBinding and cannot be assigned to other types /** @expect ts2739 */ aPlaceholder = model.bindList("anArray", context); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-interface.ts b/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-interface.ts index 413187f..5024a76 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-interface.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-interface.ts @@ -73,16 +73,16 @@ import { TypedJSONModel } from "../../model"; * Check model.bindList **********************************************************************************************************************/ -/** @expect ok */ let ListBinding: JSONListBinding = model.bindList("anArray", context); -/** @expect ok */ ListBinding = model.bindList("anArrayOfArrays/0", context); -/** @expect ok */ ListBinding = model.bindList("anObjectWithArray/anArray", context); +/** @expect ok */ let listBinding: JSONListBinding = model.bindList("anArray", context); +/** @expect ok */ listBinding = model.bindList("anArrayOfArrays/0", context); +/** @expect ok */ listBinding = model.bindList("anObjectWithArray/anArray", context); // incorrect binding paths -/** @expect ts2769 */ ListBinding = model.bindList("aJsonSafeArray/0", context); -/** @expect ts2769 */ ListBinding = model.bindList("anArrayOfArrays/0/0", context); -/** @expect ts2769 */ ListBinding = model.bindList("anObjectWithArray/anArray/0", context); -/** @expect ts2769 */ ListBinding = model.bindList("anArrayOfPlaceholders/0", context); -/** @expect ts2769 */ ListBinding = model.bindList("anArrayOfObjects/0", context); +/** @expect ts2769 */ listBinding = model.bindList("aJsonSafeArray/0", context); +/** @expect ts2769 */ listBinding = model.bindList("anArrayOfArrays/0/0", context); +/** @expect ts2769 */ listBinding = model.bindList("anObjectWithArray/anArray/0", context); +/** @expect ts2769 */ listBinding = model.bindList("anArrayOfPlaceholders/0", context); +/** @expect ts2769 */ listBinding = model.bindList("anArrayOfObjects/0", context); // bindList always returns a JSONListBinding and cannot be assigned to other types /** @expect ts2739 */ aPlaceholder = model.bindList("anArray", context); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-typeAlias.ts b/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-typeAlias.ts index 59e2a11..a97fed2 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-typeAlias.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/relative-complex-typeAlias.ts @@ -75,16 +75,16 @@ model.getProperty("/root/aPlaceholder", context); * Check model.bindList **********************************************************************************************************************/ -/** @expect ok */ let ListBinding: JSONListBinding = model.bindList("anArray", context); -/** @expect ok */ ListBinding = model.bindList("anArrayOfArrays/0", context); -/** @expect ok */ ListBinding = model.bindList("anObjectWithArray/anArray", context); +/** @expect ok */ let listBinding: JSONListBinding = model.bindList("anArray", context); +/** @expect ok */ listBinding = model.bindList("anArrayOfArrays/0", context); +/** @expect ok */ listBinding = model.bindList("anObjectWithArray/anArray", context); // incorrect binding paths -/** @expect ts2769 */ ListBinding = model.bindList("aJsonSafeArray/0", context); -/** @expect ts2769 */ ListBinding = model.bindList("anArrayOfArrays/0/0", context); -/** @expect ts2769 */ ListBinding = model.bindList("anObjectWithArray/anArray/0", context); -/** @expect ts2769 */ ListBinding = model.bindList("anArrayOfPlaceholders/0", context); -/** @expect ts2769 */ ListBinding = model.bindList("anArrayOfObjects/0", context); +/** @expect ts2769 */ listBinding = model.bindList("aJsonSafeArray/0", context); +/** @expect ts2769 */ listBinding = model.bindList("anArrayOfArrays/0/0", context); +/** @expect ts2769 */ listBinding = model.bindList("anObjectWithArray/anArray/0", context); +/** @expect ts2769 */ listBinding = model.bindList("anArrayOfPlaceholders/0", context); +/** @expect ts2769 */ listBinding = model.bindList("anArrayOfObjects/0", context); // bindList always returns a JSONListBinding and cannot be assigned to other types /** @expect ts2739 */ aPlaceholder = model.bindList("anArray", context); From 7e02d89059b83e31841495043f4e6bbd36440345 Mon Sep 17 00:00:00 2001 From: viktorsperling Date: Mon, 2 Feb 2026 11:14:21 +0100 Subject: [PATCH 7/7] feat(dts-generator): add bindList declarations to TypedJSONModel --- .../src/resources/typed-json-model.d.ts | 61 +++++++++++++++++++ .../typed-json-model/webapp/model/model.ts | 4 +- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/packages/dts-generator/src/resources/typed-json-model.d.ts b/packages/dts-generator/src/resources/typed-json-model.d.ts index 5d33d33..25a5878 100644 --- a/packages/dts-generator/src/resources/typed-json-model.d.ts +++ b/packages/dts-generator/src/resources/typed-json-model.d.ts @@ -1,5 +1,8 @@ declare module "sap/ui/model/json/TypedJSONModel" { + import Filter from "sap/ui/model/Filter"; + import Sorter from "sap/ui/model/Sorter"; import JSONModel from "sap/ui/model/json/JSONModel"; + import JSONListBinding from "sap/ui/model/json/JSONListBinding"; import TypedJSONContext from "sap/ui/model/json/TypedJSONContext"; import Context from "sap/ui/model/Context"; @@ -30,6 +33,24 @@ declare module "sap/ui/model/json/TypedJSONModel" { oContext: TypedJSONContext, ): PropertyByRelativeBindingPath; + bindList>( + sPath: Path, + oContext?: undefined, + aSorters?: Sorter | Sorter[], + aFilters?: Filter | Filter[], + mParameters?: object, + ): JSONListBinding; + bindList< + Path extends RelativeListBindingPath, + Root extends AbsoluteBindingPath, + >( + sPath: Path, + oContext?: TypedJSONContext, + aSorters?: Sorter | Sorter[], + aFilters?: Filter | Filter[], + mParameters?: object, + ): JSONListBinding; + setData(oData: Data, bMerge?: boolean): void; // setProperty with AbsoluteBindingPath (context === undefined), @@ -82,6 +103,25 @@ declare module "sap/ui/model/json/TypedJSONModel" { : // if T is not of type object: never; + /** + * Valid absolute binding path for underlying `Array` types. + * + * @example + * type SalesOrder = { id: string, items: string[] }; + * type PathInObject = PathInJSONModel; // "/id" | "/items" + * let path: PathInObject = "/items"; // ok + * path = "/id"; // error + * path = "/items/0"; // error, since an element in the array is a string + */ + export type AbsoluteListBindingPath = { + [Path in AbsoluteBindingPath]: PropertyByAbsoluteBindingPath< + Type, + Path + > extends Array + ? Path + : never; + }[AbsoluteBindingPath]; + /** * Valid relative binding path in a JSONModel. * The root of the path is defined by the given root string. @@ -98,6 +138,27 @@ declare module "sap/ui/model/json/TypedJSONModel" { ? Rest : never; + /** + * Valid relative binding path for underlying `Array` types. + * The root of the path is defined by the given root string. + * + * @example + * type SalesOrder = { buyer: { id: string, items: string[] } }; + * type PathRelativeToSalesOrder = RelativeListBindingPath; // "id" | "items" + */ + export type RelativeListBindingPath< + Type, + Root extends AbsoluteBindingPath, + > = { + [Path in RelativeBindingPath]: PropertyByRelativeBindingPath< + Type, + Root, + Path + > extends Array + ? Path + : never; + }[RelativeBindingPath]; + /** * The type of a property in a JSONModel identified by the given path. * Counterpart to {@link AbsoluteBindingPath}. diff --git a/test-packages/typed-json-model/webapp/model/model.ts b/test-packages/typed-json-model/webapp/model/model.ts index b72443d..0b00cb5 100644 --- a/test-packages/typed-json-model/webapp/model/model.ts +++ b/test-packages/typed-json-model/webapp/model/model.ts @@ -1,8 +1,8 @@ import Context from "sap/ui/model/Context"; +import Filter from "sap/ui/model/Filter"; +import Sorter from "sap/ui/model/Sorter"; import JSONModel from "sap/ui/model/json/JSONModel"; import JSONListBinding from "sap/ui/model/json/JSONListBinding"; -import Sorter from "sap/ui/model/Sorter"; -import Filter from "sap/ui/model/Filter"; import { AbsoluteBindingPath, AbsoluteListBindingPath,