Skip to content

Commit 123fc72

Browse files
Added some additional typing to the TS SDK (#3245)
# Description of Changes This just constrains the types of rows from `any` to `Record<string, any>`. # API and ABI breaking changes Not breaking, purely internal. # Expected complexity level and risk 1 # Testing - [x] Just the automated tests
1 parent cfb185a commit 123fc72

4 files changed

Lines changed: 57 additions & 38 deletions

File tree

sdks/typescript/packages/sdk/src/client_cache.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export class ClientCache {
55
/**
66
* The tables in the database.
77
*/
8-
tables: Map<string, TableCache>;
8+
tables: Map<string, TableCache<any>>;
99

1010
constructor() {
1111
this.tables = new Map();
@@ -16,7 +16,9 @@ export class ClientCache {
1616
* @param name The name of the table.
1717
* @returns The table
1818
*/
19-
getTable(name: string): TableCache {
19+
getTable<RowType extends Record<string, any>>(
20+
name: string
21+
): TableCache<RowType> {
2022
const table = this.tables.get(name);
2123

2224
// ! This should not happen as the table should be available but an exception is thrown just in case.
@@ -30,10 +32,10 @@ export class ClientCache {
3032
return table;
3133
}
3234

33-
getOrCreateTable<RowType>(
35+
getOrCreateTable<RowType extends Record<string, any>>(
3436
tableTypeInfo: TableRuntimeTypeInfo
3537
): TableCache<RowType> {
36-
let table: TableCache;
38+
let table: TableCache<RowType>;
3739
if (!this.tables.has(tableTypeInfo.tableName)) {
3840
table = new TableCache<RowType>(tableTypeInfo);
3941
this.tables.set(tableTypeInfo.tableName, table);

sdks/typescript/packages/sdk/src/db_connection_impl.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,9 @@ export class DbConnectionImpl<
483483
const parsedTableUpdates = await parseDatabaseUpdate(
484484
message.value.update
485485
);
486-
const subscribeAppliedMessage: SubscribeAppliedMessage = {
486+
const subscribeAppliedMessage: SubscribeAppliedMessage<
487+
Record<string, any>
488+
> = {
487489
tag: 'SubscribeApplied',
488490
queryId: message.value.queryId.id,
489491
tableUpdates: parsedTableUpdates,
@@ -495,7 +497,9 @@ export class DbConnectionImpl<
495497
const parsedTableUpdates = await parseDatabaseUpdate(
496498
message.value.update
497499
);
498-
const unsubscribeAppliedMessage: UnsubscribeAppliedMessage = {
500+
const unsubscribeAppliedMessage: UnsubscribeAppliedMessage<
501+
Record<string, any>
502+
> = {
499503
tag: 'UnsubscribeApplied',
500504
queryId: message.value.queryId.id,
501505
tableUpdates: parsedTableUpdates,

sdks/typescript/packages/sdk/src/message_types.ts

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import { Identity } from 'spacetimedb';
44
import type { TableUpdate } from './table_cache.ts';
55
import { Timestamp } from 'spacetimedb';
66

7-
export type InitialSubscriptionMessage = {
7+
export type InitialSubscriptionMessage<RowType extends Record<string, any>> = {
88
tag: 'InitialSubscription';
9-
tableUpdates: TableUpdate[];
9+
tableUpdates: TableUpdate<RowType>[];
1010
};
1111

12-
export type TransactionUpdateMessage = {
12+
export type TransactionUpdateMessage<RowType extends Record<string, any>> = {
1313
tag: 'TransactionUpdate';
14-
tableUpdates: TableUpdate[];
14+
tableUpdates: TableUpdate<RowType>[];
1515
identity: Identity;
1616
connectionId: ConnectionId | null;
1717
reducerInfo?: {
@@ -24,10 +24,11 @@ export type TransactionUpdateMessage = {
2424
energyConsumed: bigint;
2525
};
2626

27-
export type TransactionUpdateLightMessage = {
28-
tag: 'TransactionUpdateLight';
29-
tableUpdates: TableUpdate[];
30-
};
27+
export type TransactionUpdateLightMessage<RowType extends Record<string, any>> =
28+
{
29+
tag: 'TransactionUpdateLight';
30+
tableUpdates: TableUpdate<RowType>[];
31+
};
3132

3233
export type IdentityTokenMessage = {
3334
tag: 'IdentityToken';
@@ -36,16 +37,16 @@ export type IdentityTokenMessage = {
3637
connectionId: ConnectionId;
3738
};
3839

39-
export type SubscribeAppliedMessage = {
40+
export type SubscribeAppliedMessage<RowType extends Record<string, any>> = {
4041
tag: 'SubscribeApplied';
4142
queryId: number;
42-
tableUpdates: TableUpdate[];
43+
tableUpdates: TableUpdate<RowType>[];
4344
};
4445

45-
export type UnsubscribeAppliedMessage = {
46+
export type UnsubscribeAppliedMessage<RowType extends Record<string, any>> = {
4647
tag: 'UnsubscribeApplied';
4748
queryId: number;
48-
tableUpdates: TableUpdate[];
49+
tableUpdates: TableUpdate<RowType>[];
4950
};
5051

5152
export type SubscriptionError = {
@@ -54,11 +55,12 @@ export type SubscriptionError = {
5455
error: string;
5556
};
5657

57-
export type Message =
58-
| InitialSubscriptionMessage
59-
| TransactionUpdateMessage
60-
| TransactionUpdateLightMessage
61-
| IdentityTokenMessage
62-
| SubscribeAppliedMessage
63-
| UnsubscribeAppliedMessage
64-
| SubscriptionError;
58+
export type Message<RowType extends Record<string, any> = Record<string, any>> =
59+
60+
| InitialSubscriptionMessage<RowType>
61+
| TransactionUpdateMessage<RowType>
62+
| TransactionUpdateLightMessage<RowType>
63+
| IdentityTokenMessage
64+
| SubscribeAppliedMessage<RowType>
65+
| UnsubscribeAppliedMessage<RowType>
66+
| SubscriptionError;

sdks/typescript/packages/sdk/src/table_cache.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,21 @@ import {
88
import { stdbLogger } from './logger.ts';
99
import type { ComparablePrimitive } from 'spacetimedb';
1010

11-
export type Operation = {
11+
export type Operation<
12+
RowType extends Record<string, any> = Record<string, any>,
13+
> = {
1214
type: 'insert' | 'delete';
1315
// For tables with a primary key, this is the primary key value, as a primitive or string.
1416
// Otherwise, it is an encoding of the full row.
1517
rowId: ComparablePrimitive;
16-
// TODO: Refine this type to at least reflect that it is a product.
17-
row: any;
18+
row: RowType;
1819
};
1920

20-
export type TableUpdate = {
21+
export type TableUpdate<
22+
RowType extends Record<string, any> = Record<string, any>,
23+
> = {
2124
tableName: string;
22-
operations: Operation[];
25+
operations: Operation<RowType>[];
2326
};
2427

2528
export type PendingCallback = {
@@ -30,7 +33,9 @@ export type PendingCallback = {
3033
/**
3134
* Builder to generate calls to query a `table` in the database
3235
*/
33-
export class TableCache<RowType = any> {
36+
export class TableCache<
37+
RowType extends Record<string, any> = Record<string, any>,
38+
> {
3439
private rows: Map<ComparablePrimitive, [RowType, number]>;
3540
private tableTypeInfo: TableRuntimeTypeInfo;
3641
private emitter: EventEmitter<'insert' | 'delete' | 'update'>;
@@ -57,18 +62,24 @@ export class TableCache<RowType = any> {
5762
/**
5863
* @returns The values of the rows in the table
5964
*/
60-
iter(): any[] {
65+
iter(): RowType[] {
6166
return Array.from(this.rows.values()).map(([row]) => row);
6267
}
6368

6469
applyOperations = (
65-
operations: Operation[],
70+
operations: Operation<RowType>[],
6671
ctx: EventContextInterface
6772
): PendingCallback[] => {
6873
const pendingCallbacks: PendingCallback[] = [];
6974
if (this.tableTypeInfo.primaryKeyInfo !== undefined) {
70-
const insertMap = new Map<ComparablePrimitive, [Operation, number]>();
71-
const deleteMap = new Map<ComparablePrimitive, [Operation, number]>();
75+
const insertMap = new Map<
76+
ComparablePrimitive,
77+
[Operation<RowType>, number]
78+
>();
79+
const deleteMap = new Map<
80+
ComparablePrimitive,
81+
[Operation<RowType>, number]
82+
>();
7283
for (const op of operations) {
7384
if (op.type === 'insert') {
7485
const [_, prevCount] = insertMap.get(op.rowId) || [op, 0];
@@ -177,7 +188,7 @@ export class TableCache<RowType = any> {
177188

178189
insert = (
179190
ctx: EventContextInterface,
180-
operation: Operation,
191+
operation: Operation<RowType>,
181192
count: number = 1
182193
): PendingCallback | undefined => {
183194
const [_, previousCount] = this.rows.get(operation.rowId) || [
@@ -200,7 +211,7 @@ export class TableCache<RowType = any> {
200211

201212
delete = (
202213
ctx: EventContextInterface,
203-
operation: Operation,
214+
operation: Operation<RowType>,
204215
count: number = 1
205216
): PendingCallback | undefined => {
206217
const [_, previousCount] = this.rows.get(operation.rowId) || [

0 commit comments

Comments
 (0)