redux-toolkit icon indicating copy to clipboard operation
redux-toolkit copied to clipboard

Review and update RTKQ TS type visibility

Open markerikson opened this issue 4 years ago • 14 comments

We kinda hand-waved reviewing some of the TS types. We should make sure that we've got exactly the stuff we want marked as public.

markerikson avatar Jun 07 '21 03:06 markerikson

Not perfectly sure this is the right place for a comment on this, but I've run into trouble with this. I'd like to be able to pass the result of a query hook into a view component, but to do so cleanly would need this to work, I think:

import { UseQueryResult } from "@reduxjs/toolkit/dist/query"; // "has no exported member..."

For now, I can just copy-paste the type definition from here:

image

but it seems we'd want to be able to import that directly.

kalzoo avatar Sep 30 '21 17:09 kalzoo

This is just a simplified type, correct? Normally, data is not optional if isSuccess is true. But something like this really is needed if I want to move the call of a query hook into a custom hook that returns the result directly. Otherwise, I cannot specify the return type of that custom hook.

function useCustomHook(): ??? {
  const result = useSomeQuery()
  return result
}

I tried using ReturnType<typeof useSomeQuery> but that doesn't work either because this type's property isSuccess is of type any. This means it cannot be used in a conditional.

alinnert avatar Nov 29 '22 20:11 alinnert

@alinnert are you looking for these types? https://github.com/reduxjs/redux-toolkit/pull/2580/files

phryneas avatar Nov 29 '22 20:11 phryneas

@phryneas technically I'm looking for UseQueryHookResult, yes. But I cannot use it for two reasons: When I hover over the result variable in VSCode it doesn't show me the full type because it's too long. A part of it is truncated. That means I don't know how to fully use that type. The second reason is the result type includes UseQueryStateDefaultResult<...> which isn't exported and therefore I cannot access.

alinnert avatar Nov 29 '22 21:11 alinnert

@alinnert What do you mean "cannot access"?

Usage should be UseQueryHookResult<YourDataTypeHere>.

markerikson avatar Nov 29 '22 21:11 markerikson

If it is truncated, hold down Ctrl and click on it and it will give you the full definition.

phryneas avatar Nov 29 '22 21:11 phryneas

What do you mean "cannot access"?

Nevermind. I meant I cannot import (= access) UseQueryStateDefaultResult because it's not exported. But it shouldn't be necessary anyway.

Okay, now I know that YourDataTypeHere needs to be of type QueryDefinition<...>. But I still don't know how to get that type. I know that postQuoteDocumentMetadataById (result of builder.query()) in the code below is such a QueryDefinition. Do I need this one? But I don't know how I get that type from here into my custom hook.

The closest I get is UseQueryHookResult<typeof externalSFApi['endpoints']['postQuoteDocumentMetadataById']>. But that's only ApiEndpointQuery<QueryDefinition<...>>. That's close but it still doesn't work. What am I missing?

import { createApi } from '@reduxjs/toolkit/query/react'
import { ApiDocumentMetadata } from '../../services/request/apiTypes/documentMetadata'
import { baseQuery } from './baseQuery'

export const externalSFApi = createApi({
  reducerPath: 'externalSFApi',
  baseQuery,
  endpoints: (builder) => ({
    postQuoteDocumentMetadataById: builder.query<
      ApiDocumentMetadata,
      { sfId: string; productId: string }
    >({
      query: ({ sfId, productId }) => ({
        method: 'post',
        url: `quote/document/metadata/${sfId}/${productId}`,
      }),
    }),
  }),
})

export const { usePostQuoteDocumentMetadataByIdQuery } = externalSFApi

alinnert avatar Nov 29 '22 21:11 alinnert

No, you're making this a lot more complicated than it needs to be :)

It's whatever data type your hook returns. Like, for a getPokemon endpoint / hook, it'd be UseQueryHookResult<Pokemon>. So in this case, UseQueryHookResult<ApiDocumentMetadata>.

All that said, is there a reason you can't let TS infer the return type of your custom hook?

markerikson avatar Nov 29 '22 21:11 markerikson

I tried this at first, but UseQueryHookResult<ApiDocumentMetadata> gives me the error "Type 'ApiDocumentMetadata' does not satisfy the constraint 'QueryDefinition<any, any, any, any, string>'.". That's how I ended up looking for QueryDefinition.

You mean skipping the return type definition? Basically, because of how we setup ESLint. It would result in an error on that end. Generally, I think explicit return types are a good idea. But I've noticed that typing custom hooks can get really difficult.

alinnert avatar Nov 29 '22 22:11 alinnert

It's TypedUseQueryStateResult<ResultType, QueryArgument, BaseQuery> and you probably can just do TypedUseQueryStateResult<YourResult, unknown, any>

phryneas avatar Nov 29 '22 22:11 phryneas

Whoops, my bad! That's what I get for trying to answer this without looking at the code :)

markerikson avatar Nov 29 '22 22:11 markerikson

Okay, that works. Thank you very much! But could this potentially be made a little more straightforward? I'd need to look into this in more detail but maybe something like QueryHookResult<typeof apiInstance, 'nameOfTheEndpoint'>? Because apiInstance already has all the information that TypedUseQueryStateResult needs.

alinnert avatar Nov 29 '22 22:11 alinnert

Sorry, but no. This is already a quite niche use case and I don't think that adding a lot more helpers here will bring substantial benefit - but it will add a maintenance burden.

phryneas avatar Nov 29 '22 23:11 phryneas