From f370f62cdcf820b25e7625aae5b57b9f0dc33615 Mon Sep 17 00:00:00 2001 From: Andrew Bulat Date: Fri, 6 Dec 2024 03:06:57 +0000 Subject: [PATCH] Update `LiveMap.get` to have `undefined` as a possible return value This is a temporary solution for handling the access API for tombstoned objects. See comment in Confluence for the relevant discussion [1]. The return type for the LiveCounter.value is not changed as part of this commit, as the tombstoned LiveCounter has a value of 0 for its data. [1] https://ably.atlassian.net/wiki/spaces/LOB/pages/3556671496/LODR-026+Correctness+of+OBJECT_DELETE?focusedCommentId=3593928705 --- ably.d.ts | 6 ++++-- src/plugins/liveobjects/livemap.ts | 3 ++- .../browser/template/src/index-liveobjects.ts | 14 +++++++------- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/ably.d.ts b/ably.d.ts index cd60057e7..eaccb3ccb 100644 --- a/ably.d.ts +++ b/ably.d.ts @@ -2105,10 +2105,12 @@ export declare interface LiveMap extends LiveObject(key: TKey): T[TKey] extends StateValue ? T[TKey] : T[TKey] | undefined; + get(key: TKey): T[TKey] | undefined; /** * Returns the number of key/value pairs in the map. diff --git a/src/plugins/liveobjects/livemap.ts b/src/plugins/liveobjects/livemap.ts index 7271beb5b..3051e89da 100644 --- a/src/plugins/liveobjects/livemap.ts +++ b/src/plugins/liveobjects/livemap.ts @@ -80,12 +80,13 @@ export class LiveMap extends LiveObject(key: TKey): T[TKey] extends StateValue ? T[TKey] : T[TKey] | undefined { + get(key: TKey): T[TKey] | undefined { const element = this._dataRef.data.get(key); if (element === undefined) { diff --git a/test/package/browser/template/src/index-liveobjects.ts b/test/package/browser/template/src/index-liveobjects.ts index 00763d46b..4059cc01d 100644 --- a/test/package/browser/template/src/index-liveobjects.ts +++ b/test/package/browser/template/src/index-liveobjects.ts @@ -24,14 +24,14 @@ globalThis.testAblyPackage = async function () { const size: number = root.size(); // check custom user provided typings via LiveObjectsTypes are working: + // any LiveMap.get() call can return undefined, as the LiveMap itself can be tombstoned (has empty state), + // or referenced object is tombstoned. // keys on a root: - const aNumber: number = root.get('numberKey'); - const aString: string = root.get('stringKey'); - const aBoolean: boolean = root.get('booleanKey'); - const couldBeUndefined: string | undefined = root.get('couldBeUndefined'); + const aNumber: number | undefined = root.get('numberKey'); + const aString: string | undefined = root.get('stringKey'); + const aBoolean: boolean | undefined = root.get('booleanKey'); + const userProvidedUndefined: string | undefined = root.get('couldBeUndefined'); // live objects on a root: - // LiveMap.get can still return undefined for LiveObject typed properties even if custom typings have them as non-optional. - // objects can be tombstoned and result in the undefined value const counter: Ably.LiveCounter | undefined = root.get('counterKey'); const map: LiveObjectsTypes['root']['mapKey'] | undefined = root.get('mapKey'); // check string literal types works @@ -63,5 +63,5 @@ globalThis.testAblyPackage = async function () { // check can provide custom types for the getRoot method, ignoring global LiveObjectsTypes interface const explicitRoot: Ably.LiveMap = await liveObjects.getRoot(); - const someOtherKey: string = explicitRoot.get('someOtherKey'); + const someOtherKey: string | undefined = explicitRoot.get('someOtherKey'); };