Skip to content

Question: how to use TypedQueryStateSelector with TypedUseQueryStateResult to build reusable query selectors #5280

@CosmaTrix

Description

@CosmaTrix

Hi there!

I've been having some issues building reusable query selectors. Let's assume I have this simple feature

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
import type { FC } from 'react';

interface Profile {
  firstName: string;
  lastName: string;
  age: number;
}

const profileApi = createApi({
  baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
  endpoints: (builder) => ({
    getProfile: builder.query<Profile, void>({
      query: () => 'profile',
    }),
  }),
});

const ProfileFullName: FC = () => {
  const profile = profileApi.useGetProfileQuery(undefined, {
    selectFromResult(state) {
      if (state.isSuccess) {
        return {
          ...state,
          data: {
            fullName: `${state.data.firstName} ${state.data.lastName}`,
          },
        };
      }

      return state;
    },
  });

  if (profile.isLoading) return <span>Loading...</span>;
  if (profile.isError) return <span>Error loading profile</span>;

  return profile.isSuccess && <span>{profile.data.fullName}</span>;
};

No rocket science, just a profile API and a component using it. The hook uses selectFromResult to extract the full name from the returned data. This is a pattern I use in many of my components.
Now I'd like to make it reusable while keeping all the useful properties RTK Query returns (like isLoading, data when isSuccess is true, etc...).

I came up with using TypedUseQueryStateResult to get all those states

import type { TypedQueryStateSelector, TypedUseQueryStateResult } from '@reduxjs/toolkit/query/react';

const selectFullName: TypedQueryStateSelector<
  Profile,
  undefined,
  ReturnType<typeof fetchBaseQuery>,
  TypedUseQueryStateResult<{ fullName: string }, undefined, ReturnType<typeof fetchBaseQuery>>
> = (state) => {
  if (state.isSuccess) {
    return {
      ...state,
      data: {
        fullName: `${state.data.firstName} ${state.data.lastName}`,
      },
    };
  }

  return state;
};

However, TS gives me back the following error

          Types of property 'currentData' are incompatible.
            Type 'Profile | undefined' is not assignable to type '{ fullName: string; } | undefined'.
              Property 'fullName' is missing in type 'Profile' but required in type '{ fullName: string; }'.ts(2322)

Any ideas? Or tricks to make this happen?

Metadata

Metadata

Assignees

No one assigned

    Labels

    QuestionFurther information is requestedRTK-QueryIssues related to Redux-Toolkit-QueryTypeScriptIssues related to TypeScript.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions