Skip to content

Commit 4f7688a

Browse files
NicolappsConvex, Inc.
authored andcommitted
Warn when using an async optimistic update handler (#37670)
`withOptimisticUpdate` takes an `OptimisticUpdate` (`(…) => void`) which is ran synchronously. But in TypeScript, `() => Promise<void>` is a valid subtype of it, so using an asynchronous handler won’t fail at compile time. When it runs, the behavior is very surprising as local store changes would suddenly start to be ignored as soon as the handler starts using `await` (even for awaiting a function that returns instantly). It’s surprisingly difficult to fix that problem at compile time. Since functions that implicitly return `undefined` are typed as `() => void` and not `() => undefined`, changing `OptimisticUpdate` to be `() => undefined` doesn’t work. The next best option is to add a runtime warning when the user returns a promise from an optimistic update handler, in order to help the developer identify what’s going wrong. GitOrigin-RevId: 4f02221f153f482881163a3c1949ba45e62a1994
1 parent c78c4d8 commit 4f7688a

File tree

1 file changed

+9
-1
lines changed
  • npm-packages/convex/src/browser/sync

1 file changed

+9
-1
lines changed

npm-packages/convex/src/browser/sync/client.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -781,7 +781,15 @@ export class BaseConvexClient {
781781
const optimisticUpdate = options.optimisticUpdate;
782782
if (optimisticUpdate !== undefined) {
783783
const wrappedUpdate = (localQueryStore: OptimisticLocalStore) => {
784-
optimisticUpdate(localQueryStore, mutationArgs);
784+
const result: unknown = optimisticUpdate(
785+
localQueryStore,
786+
mutationArgs,
787+
);
788+
if (result instanceof Promise) {
789+
this.logger.warn(
790+
"Optimistic update handler returned a Promise. Optimistic updates should be synchronous.",
791+
);
792+
}
785793
};
786794

787795
const changedQueryTokens =

0 commit comments

Comments
 (0)