Skip to content

Conversation

@chriszarate
Copy link
Contributor

What?

Introduce a type-safe wrapper for Y.Map.

Why?

The build-in typings for Y.Map have limitations. By default, the type of Y.Map values is the union of all possible values of the map. Its non-specificity requires aggressive type narrowing or (usually) type casting / destruction with as.

See #73946 for an example bug that can be prevented with stronger type safety.

How?

This PR introduces YMapWrap, which can infer the correct value type based on the provided key. It is a type overlay and does not change the runtime behavior of Y.Map. Using this type, we can remove almost all of uses of as in our CRDT-related code.

We also benefit from more clearly representing the data structure encoded in the CRDT document. See YPostRecord and YBlockRecord.

Testing Instructions

These changes are covered by existing tests, but you can check out this branch and confirm the added type safety by trying to introduce type bugs.

Before

interface SomeRecord {
  foo: string;
  bar: number;
}

const doc = new Y.Doc();
const someRecordMap = doc.getMap( 'some_record' );

someRecordMap.set( 'foo', 1234 ); // no error!
someRecordMap.get( 'bar' ) // return type: string | number | undefined

After

interface SomeRecord {
  foo: string;
  bar: number;
}

const doc = new Y.Doc();
const someRecordMap = getMap< SomeRecord >( doc, 'some_record' );

someRecordMap.set( 'foo', 1234 ); // TS Error: Argument of type 'number' is not assignable....
someRecordMap.get( 'bar' ) // return type: number | undefined

Testing Instructions for Keyboard

n/a

@chriszarate chriszarate requested a review from nerrad as a code owner December 12, 2025 03:05
@chriszarate chriszarate added [Feature] Real-time Collaboration Phase 3 of the Gutenberg roadmap around real-time collaboration [Type] Experimental Experimental feature or API. labels Dec 12, 2025
@github-actions
Copy link

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: chriszarate <[email protected]>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

Base automatically changed from fix/crdt-ytext-guard to trunk December 15, 2025 16:05
* Real-time collaboration: Improve type safety with YMapWrap

* Strict type for type guard input
@chriszarate chriszarate force-pushed the improve/ymap-type-safety branch from 0f6fe70 to 5fc4f53 Compare December 15, 2025 21:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] Real-time Collaboration Phase 3 of the Gutenberg roadmap around real-time collaboration [Type] Experimental Experimental feature or API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants