If you are using TypeScript in your project, you can leverage built-in TypeScript support to ensure type safety and enable autocompletion when working with the channel object.
Provide a type for the channel object
You can provide a type parameter to the channel.object.get<T>() method to specify the expected structure of the channel object:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { LiveCounter, LiveMap } from 'ably/liveobjects';
// Define the expected structure of your channel object
type MyObject = {
visits: LiveCounter;
reactions: LiveMap<{
likes: LiveCounter;
hearts: LiveCounter;
}>;
settings: LiveMap<{
theme: string;
notifications: boolean;
}>;
};
// Get a typed PathObject for the channel
const myObject = await channel.object.get<MyObject>();This enables TypeScript to infer the correct types when accessing and mutating objects. TypeScript surfaces the correct set of methods that are expected for the current Instance or PathObject and infers the correct arguments and return values for all methods:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// TypeScript knows 'visits' is a LiveCounter
const visits = myObject.get('visits');
await visits.increment(5); // Type-safe
// TypeScript knows the structure of 'reactions'
const reactions = myObject.get('reactions');
const likes = reactions.get('likes');
await likes.increment(1); // Type-safe
// TypeScript knows 'theme' is a string
const theme = myObject.get('settings').get('theme');
const themeValue: string | undefined = theme.value();
// Type errors are caught at compile time
await reactions.set('likes', 'invalid');
// Error: Argument of type 'string' is not assignable to parameter of type 'LiveCounter'When obtaining Instance objects, TypeScript automatically infers the correct instance type:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type MyObject = {
visits: LiveCounter;
settings: LiveMap<{
theme: string;
}>;
};
const myObject = await channel.object.get<MyObject>();
const visits = myObject.get('visits').instance();
await visits?.increment(1); // TypeScript knows visits is an Instance of a LiveCounter
const value: number | undefined = visits?.value(); // TypeScript knows the LiveCounter has a number value
const settings = myObject.get('settings').instance();
await settings?.set('theme', 'dark'); // TypeScript knows settings is an Instance of a LiveMap
const theme: string | undefined = settings?.get('theme');TypeScript also infers the correct instance type when using batch operations:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
type MyObject = {
visits: LiveCounter;
settings: LiveMap<{
theme: string;
}>;
};
const myObject = await channel.object.get<MyObject>();
await myObject.batch((ctx) => {
const visits = ctx.get('visits');
visits?.increment(1); // TypeScript knows visits is a LiveCounter
const value: number | undefined = visits?.value(); // TypeScript knows the LiveCounter has a number value
const settings = ctx.get('settings');
settings?.set('theme', 'dark'); // TypeScript knows settings is a LiveMap
const theme: string | undefined = settings?.get('theme');
});Define reusable types
You can define and export types for reuse across your application:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// types/liveobjects.ts
import { LiveCounter, LiveMap } from 'ably/liveobjects';
export type ReactionsType = {
likes: LiveCounter;
hearts: LiveCounter;
fire: LiveCounter;
};
export type UserProfileType = {
name: string;
score: LiveCounter;
settings: LiveMap<{
theme: string;
notifications: boolean;
}>;
};
export type ChannelObjectType = {
reactions: LiveMap<ReactionsType>;
users: LiveMap<{
[userId: string]: LiveMap<UserProfileType>;
}>;
};Then import and use these types where needed:
1
2
3
4
5
6
7
8
9
10
11
import type { ChannelObjectType } from './types/liveobjects';
const myObject = await channel.object.get<ChannelObjectType>();
// Fully typed access
const userScore = myObject
.get('users')
.get('user123')
.get('score');
await userScore.increment(10); // Type-safeUse per-channel types
When your application uses multiple channels with different object structures, you can specify different types for each:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Define types for different channels
type ReactionsChannelObject = {
likes: LiveCounter;
hearts: LiveCounter;
};
type LeaderboardChannelObject = {
players: LiveMap<{
[playerId: string]: LiveMap<{
name: string;
score: LiveCounter;
}>;
}>;
};
// Get typed objects for different channels
const reactionsChannel = client.channels.get('reactions');
const reactions = await reactionsChannel.object.get<ReactionsChannelObject>();
const leaderboardChannel = client.channels.get('leaderboard');
const leaderboard = await leaderboardChannel.object.get<LeaderboardChannelObject>();
// Each channel has its own type safety
await reactions.get('likes').increment(1); // Type-safe for reactions
const players = leaderboard.get('players'); // Type-safe for leaderboard