Skip to content

Updatable list elements are not assignable to themselves #5363

Description

@PatrykWalach

I have a component, with:

  1. useFragment reading list of elements
  2. mutation pushing a new element in updater
// 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.

// 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:

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:

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions