Skip to content

Commit 9cffcbb

Browse files
committed
Move types required for user-provided LiveObjects typings to ably.d.ts
Add globally defined `LiveObjectsTypes` to `intentionallyNotExported` [1] list for `typedoc`, as typedocs does not include documentation for the globally defined interfaces and complains that "__global.LiveObjectsTypes, defined in ./ably.d.ts, is referenced by ably.DefaultRoot but not included in the documentation." [1] https://typedoc.org/documents/Options.Validation.html#intentionallynotexported
1 parent 4f6ef44 commit 9cffcbb

File tree

5 files changed

+61
-32
lines changed

5 files changed

+61
-32
lines changed

ably.d.ts

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2039,25 +2039,76 @@ export declare interface LiveObjects {
20392039
/**
20402040
* Retrieves the root {@link LiveMap} object for state on a channel.
20412041
*
2042+
* A type parameter can be provided to describe the structure of the LiveObjects state on the channel. By default, it uses types from the globally defined `LiveObjectsTypes` interface.
2043+
*
2044+
* You can specify custom types for LiveObjects by defining a global `LiveObjectsTypes` interface with a `root` property that conforms to {@link LiveMapType}.
2045+
*
2046+
* Example:
2047+
*
2048+
* ```typescript
2049+
* import { LiveCounter } from 'ably';
2050+
*
2051+
* type MyRoot = {
2052+
* myTypedKey: LiveCounter;
2053+
* };
2054+
*
2055+
* declare global {
2056+
* export interface LiveObjectsTypes {
2057+
* root: MyRoot;
2058+
* }
2059+
* }
2060+
* ```
2061+
*
20422062
* @returns A promise which, upon success, will be fulfilled with a {@link LiveMap} object. Upon failure, the promise will be rejected with an {@link ErrorInfo} object which explains the error.
20432063
*/
2044-
getRoot(): Promise<LiveMap>;
2064+
getRoot<T extends LiveMapType = DefaultRoot>(): Promise<LiveMap<T>>;
20452065
}
20462066

2067+
declare global {
2068+
/**
2069+
* A globally defined interface that allows users to define custom types for LiveObjects.
2070+
*/
2071+
export interface LiveObjectsTypes {
2072+
[key: string]: unknown;
2073+
}
2074+
}
2075+
2076+
/**
2077+
* Represents the type of data stored in a {@link LiveMap}.
2078+
* It maps string keys to scalar values ({@link StateValue}), or other LiveObjects.
2079+
*/
2080+
export type LiveMapType = { [key: string]: StateValue | LiveMap<LiveMapType> | LiveCounter | undefined };
2081+
2082+
/**
2083+
* The default type for the `root` object in the LiveObjects, based on the globally defined {@link LiveObjectsTypes} interface.
2084+
*
2085+
* - If no custom types are provided in `LiveObjectsTypes`, defaults to an untyped root map representation using the {@link LiveMapType} interface.
2086+
* - If a `root` type exists in `LiveObjectsTypes` and conforms to the {@link LiveMapType} interface, it is used as the type for the `root` object.
2087+
* - If the provided `root` type does not match {@link LiveMapType}, a type error message is returned.
2088+
*/
2089+
export type DefaultRoot =
2090+
// we need a way to know when no types were provided by the user.
2091+
// we expect a "root" property to be set on LiveObjectsTypes interface, e.g. it won't be "unknown" anymore
2092+
unknown extends LiveObjectsTypes['root']
2093+
? LiveMapType // no custom types provided; use the default untyped map representation for the root
2094+
: LiveObjectsTypes['root'] extends LiveMapType
2095+
? LiveObjectsTypes['root'] // "root" property exists, and it is of an expected type, we can use this interface for the root object in LiveObjects.
2096+
: `Provided type definition for the "root" object in LiveObjectsTypes is not of an expected LiveMapType`;
2097+
20472098
/**
20482099
* The `LiveMap` class represents a synchronized key/value storage, similar to a JavaScript Map, where all changes are synchronized across clients in realtime.
20492100
* Conflict-free resolution for updates follows Last Write Wins (LWW) semantics, meaning that if two clients update the same key in the map, the last change wins.
20502101
*
20512102
* Keys must be strings. Values can be another Live Object, or a primitive type, such as a string, number, boolean, or binary data (see {@link StateValue}).
20522103
*/
2053-
export declare interface LiveMap extends LiveObject<LiveMapUpdate> {
2104+
export declare interface LiveMap<T extends LiveMapType> extends LiveObject<LiveMapUpdate> {
20542105
/**
20552106
* Returns the value associated with a given key. Returns `undefined` if the key doesn't exist in a map.
20562107
*
20572108
* @param key - The key to retrieve the value for.
20582109
* @returns A {@link LiveObject}, a primitive type (string, number, boolean, or binary data) or `undefined` if the key doesn't exist in a map.
20592110
*/
2060-
get(key: string): LiveObject | StateValue | undefined;
2111+
get<TKey extends keyof T & string>(key: TKey): T[TKey];
20612112

20622113
/**
20632114
* Returns the number of key/value pairs in the map.

src/plugins/liveobjects/livemap.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import deepEqual from 'deep-equal';
22

3+
import type * as API from '../../../ably';
34
import { LiveObject, LiveObjectData, LiveObjectUpdate, LiveObjectUpdateNoop } from './liveobject';
45
import { LiveObjects } from './liveobjects';
56
import {
@@ -13,7 +14,6 @@ import {
1314
StateValue,
1415
} from './statemessage';
1516
import { DefaultTimeserial, Timeserial } from './timeserial';
16-
import { LiveMapType } from './typings';
1717

1818
export interface ObjectIdStateData {
1919
/** A reference to another state object, used to support composable state objects. */
@@ -46,7 +46,7 @@ export interface LiveMapUpdate extends LiveObjectUpdate {
4646
update: { [keyName: string]: 'updated' | 'removed' };
4747
}
4848

49-
export class LiveMap<T extends LiveMapType> extends LiveObject<LiveMapData, LiveMapUpdate> {
49+
export class LiveMap<T extends API.LiveMapType> extends LiveObject<LiveMapData, LiveMapUpdate> {
5050
constructor(
5151
liveObjects: LiveObjects,
5252
private _semantics: MapSemantics,
@@ -60,7 +60,7 @@ export class LiveMap<T extends LiveMapType> extends LiveObject<LiveMapData, Live
6060
*
6161
* @internal
6262
*/
63-
static zeroValue<T extends LiveMapType>(liveobjects: LiveObjects, objectId: string): LiveMap<T> {
63+
static zeroValue<T extends API.LiveMapType>(liveobjects: LiveObjects, objectId: string): LiveMap<T> {
6464
return new LiveMap<T>(liveobjects, MapSemantics.LWW, objectId);
6565
}
6666

@@ -70,7 +70,7 @@ export class LiveMap<T extends LiveMapType> extends LiveObject<LiveMapData, Live
7070
*
7171
* @internal
7272
*/
73-
static fromStateObject<T extends LiveMapType>(liveobjects: LiveObjects, stateObject: StateObject): LiveMap<T> {
73+
static fromStateObject<T extends API.LiveMapType>(liveobjects: LiveObjects, stateObject: StateObject): LiveMap<T> {
7474
const obj = new LiveMap<T>(liveobjects, stateObject.map?.semantics!, stateObject.objectId);
7575
obj.overrideWithStateObject(stateObject);
7676
return obj;

src/plugins/liveobjects/liveobjects.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { LiveObject, LiveObjectUpdate } from './liveobject';
88
import { LiveObjectsPool, ROOT_OBJECT_ID } from './liveobjectspool';
99
import { StateMessage } from './statemessage';
1010
import { SyncLiveObjectsDataPool } from './syncliveobjectsdatapool';
11-
import { DefaultRoot, LiveMapType } from './typings';
1211

1312
enum LiveObjectsEvents {
1413
SyncCompleted = 'SyncCompleted',
@@ -42,7 +41,7 @@ export class LiveObjects {
4241
* A user can provide an explicit type for the getRoot method to explicitly set the LiveObjects type structure on this particular channel.
4342
* This is useful when working with LiveObjects on multiple channels with different underlying data.
4443
*/
45-
async getRoot<T extends LiveMapType = DefaultRoot>(): Promise<LiveMap<T>> {
44+
async getRoot<T extends API.LiveMapType = API.DefaultRoot>(): Promise<LiveMap<T>> {
4645
// SYNC is currently in progress, wait for SYNC sequence to finish
4746
if (this._syncInProgress) {
4847
await this._eventEmitter.once(LiveObjectsEvents.SyncCompleted);

src/plugins/liveobjects/typings.ts

Lines changed: 0 additions & 22 deletions
This file was deleted.

typedoc.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,6 @@
2020
"TypeAlias",
2121
"Variable",
2222
"Namespace"
23-
]
23+
],
24+
"intentionallyNotExported": ["__global.LiveObjectsTypes"]
2425
}

0 commit comments

Comments
 (0)