#5363·relay

Updatable list elements are not assignable to themselves

Author: PatrykWalachCreated Jul 18, 2026Updated Jul 18, 2026

I have a component, with:

  1. useFragment reading list of elements
  2. mutation pushing a new element in updater
typescript
// IN RENDER:
const mediaListCollection = useFragment(
	graphql`
		fragment AddToList_mediaListCollection on MediaListCollection {
			lists {
				...AddToList_updatable
				status
				entries {
					id
					...AddToList_assignable
				}
			}
		}
	`,
	mediaListCollectionKey
)

// MUTATION:
{
	updater: (store, response) => {
		for (const list of mediaListCollection.lists ?? []) {
			if (list != null && list.status === source.status) {
				const { updatableData } =
					store.readUpdatableFragment<AddToList_updatable$key>(
						graphql`
							fragment AddToList_updatable on MediaListGroup @updatable {
								entries {
									id
									...AddToList_assignable
								}
							}
						`,
						list
					)

				if (response?.SaveMediaListEntry != null) {
					updatableData.entries = [
						...(list.entries?.filter((entry) => entry != null) ?? []),
						response.SaveMediaListEntry,
					]
				}
			}
		}
	}
}

I've noticed useFragment is causing performance issue and it doesn't have to read during render so I've moved it into the updater.

typescript

// AFTER REFACTOR:
{
	updater: (store, response) => {
		const { updatableData: mediaListCollection } =
			store.readUpdatableFragment<AddToList_mediaListCollection$key>(
				graphql`
					fragment AddToList_mediaListCollection on MediaListCollection
					@updatable {
						lists {
							status
							entries {
								id
								...AddToList_assignable
							}
						}
					}
				`,
				mediaListCollectionKey
			)

		for (const list of mediaListCollection.lists ?? []) {
			if (list != null && list.status === source.status) {
				if (response?.SaveMediaListEntry != null) {
					list.entries = [
						...(list.entries?.filter((entry) => entry != null) ?? []),
						response.SaveMediaListEntry,
					]
				}
			}
		}
	}
}

But now I get a type error when setting:

Type '{ readonly id: string; } | null | undefined' is not assignable to type '{ readonly __typename: "MediaList"; readonly __id: string; readonly " $fragmentSpreads": FragmentRefs<"AddToList_assignable">; }'.

New generated type is missing __typename and __id fields:

typescript
export type AddToList_mediaListCollection$data = {
  get lists(): ReadonlyArray<{
    status: MediaListStatus | null | undefined;
    get entries(): ReadonlyArray<{
      readonly id: string;                                       // <-- HERE ONLY ID IS GENERATED
    } | null | undefined> | null | undefined;
    set entries(value: ReadonlyArray<{
      readonly __typename: "MediaList";
      readonly __id: string;
      readonly " $fragmentSpreads": FragmentRefs<"AddToList_assignable">;
    }>);
  } | null | undefined> | null | undefined;
  set lists(value: []);
  readonly " $fragmentType": "AddToList_mediaListCollection";
};

The OLD one is:

typescript
export type AddToList_mediaListCollection$data = {
  readonly lists: ReadonlyArray<{
    readonly $updatableFragmentSpreads: FragmentRefs<"AddToList_updatable">;
    readonly entries: ReadonlyArray<{
      readonly __typename: "MediaList";
      readonly __id: string;
      readonly id: string;
      readonly " $fragmentSpreads": FragmentRefs<"AddToList_assignable">;
    } | null | undefined> | null | undefined;
    readonly status: MediaListStatus | null | undefined;
  } | null | undefined> | null | undefined;
  readonly " $fragmentType": "AddToList_mediaListCollection";
};

There's an easy workaround by selecting these missing fields manually

__typename
__id

This makes it work without runtime error, just the typescript error because the AddToList_assignable spread is missing

relay-compiler: 21.0.1