Skip to content

Commit 8005fd2

Browse files
committed
Update LiveMap.get to always return undefined value as an option for keys that reference other LiveObjects
Referenced live objects can be not valid (haven't seen a create op) and we should not surface such objects to the end user and return `undefined` instead.
1 parent 449ab52 commit 8005fd2

File tree

4 files changed

+9
-7
lines changed

4 files changed

+9
-7
lines changed

ably.d.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2103,12 +2103,12 @@ export type DefaultRoot =
21032103
*/
21042104
export declare interface LiveMap<T extends LiveMapType> extends LiveObject<LiveMapUpdate> {
21052105
/**
2106-
* Returns the value associated with a given key. Returns `undefined` if the key doesn't exist in a map.
2106+
* Returns the value associated with a given key. Returns `undefined` if the key doesn't exist in a map or if the associated {@link LiveObject} has been deleted.
21072107
*
21082108
* @param key - The key to retrieve the value for.
2109-
* @returns A {@link LiveObject}, a primitive type (string, number, boolean, or binary data) or `undefined` if the key doesn't exist in a map.
2109+
* @returns A {@link LiveObject}, a primitive type (string, number, boolean, or binary data) or `undefined` if the key doesn't exist in a map or the associated {@link LiveObject} has been deleted.
21102110
*/
2111-
get<TKey extends keyof T & string>(key: TKey): T[TKey];
2111+
get<TKey extends keyof T & string>(key: TKey): T[TKey] extends StateValue ? T[TKey] : T[TKey] | undefined;
21122112

21132113
/**
21142114
* Returns the number of key/value pairs in the map.

src/plugins/liveobjects/livemap.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData,
8585
* - If the value is not an objectId, then that value is returned.
8686
*/
8787
// force the key to be of type string as we only allow strings as key in a map
88-
get<TKey extends keyof T & string>(key: TKey): T[TKey] {
88+
get<TKey extends keyof T & string>(key: TKey): T[TKey] extends StateValue ? T[TKey] : T[TKey] | undefined {
8989
const element = this._dataRef.data.get(key);
9090

9191
if (element === undefined) {

test/package/browser/template/src/ably.config.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ type CustomRoot = {
55
stringKey: string;
66
booleanKey: boolean;
77
couldBeUndefined?: string;
8-
mapKey?: LiveMap<{
8+
mapKey: LiveMap<{
99
foo: 'bar';
1010
nestedMap?: LiveMap<{
1111
baz: 'qux';
1212
}>;
1313
}>;
14-
counterKey?: LiveCounter;
14+
counterKey: LiveCounter;
1515
};
1616

1717
declare global {

test/package/browser/template/src/index-liveobjects.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ globalThis.testAblyPackage = async function () {
3030
const aBoolean: boolean = root.get('booleanKey');
3131
const couldBeUndefined: string | undefined = root.get('couldBeUndefined');
3232
// live objects on a root:
33+
// LiveMap.get can still return undefined for LiveObject typed properties even if custom typings have them as non-optional.
34+
// objects can be tombstoned/non-valid and result in the undefined value
3335
const counter: Ably.LiveCounter | undefined = root.get('counterKey');
34-
const map: LiveObjectsTypes['root']['mapKey'] = root.get('mapKey');
36+
const map: LiveObjectsTypes['root']['mapKey'] | undefined = root.get('mapKey');
3537
// check string literal types works
3638
// need to use nullish coalescing as we didn't actually create any data on the root,
3739
// so the next calls would fail. we only need to check that TypeScript types work

0 commit comments

Comments
 (0)