data-client: Missing type inference for controller.fetch

React version (e.g., 18.2.0)

TypeScript version (if used) (e.g., 4.6.3)

Rest Hooks version (e.g., 7.1.0)

Package manager version yarn 1.22.19

Environment version N/A

Node version 16.18.1

Describe the bug Return types are correctly inferred for endpoints when used with useSuspense or useDLE, but not when using controller.fetch—they are inferred as any.

To Reproduce Steps to reproduce the behavior:

  1. Open Todo demo at https://resthooks.io/demos
  2. Replace contents of TodoListComponent.tsx with the following
import { useSuspense, useController } from '@rest-hooks/react';
import { useEffect } from 'react';
import { TodoResource, Todo } from 'resources/TodoResource';

import NewTodo from './NewTodo';
import TodoListItem from './TodoListItem';

export default function TodoListComponent() {
  const todos = useSuspense(TodoResource.getList);
  const controller = useController();

  useEffect(() => {
    (async () => {
      // const result: any
      const result = await controller.fetch(TodoResource.getList);
      console.log({ result });
    })();
  }, []);

  return (
    <div>
      {todos.map((todo) => (
        <TodoListItem key={todo.pk()} todo={todo} />
      ))}
      <NewTodo lastId={todos.length} />
    </div>
  );
}
  1. Observe that result type is inferred as any on line 15, but the logging that occurs on line 16 shows that the result has the type of the TodoResource.getList endpoint.

Expected behavior Return type should be inferred to be the schema type of the endpoint.

Additional context This is happening on my personal project but is demonstrable in the TodoList example as well. I noticed that the type return type for fetch is defined as ReturnType<E> (where E is the endpoint type) whereas useSuspense has a more complex return type but ultimately uses ResolveType<E>, where ResolveType is from @rest-hooks/normalizr

Minimum reproducable example or test case See modified TodoList example instructions above.

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 20

Most upvoted comments

Ah yes, I forgot to mention that this was done in the TodoList playground. Here’s a fork with the example file: https://stackblitz.com/edit/coinbase-rest-hooks-cgd2d5?file=src/resources/UserResource.ts

It uses the tsconfig.json that’s included with the TodoList example:

{
  "compilerOptions": {
    "outDir": "./dist",
    "baseUrl": "./src",
    "target": "esnext",
    "module": "esnext",
    "lib": ["dom", "esnext"],
    "jsx": "react-jsx",
    "declaration": true,
    "strict": true,
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "types": ["@anansi/webpack-config/types"],
    "paths": {
      "resources/*": ["resources/*"]
    },
    "noEmit": true
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}

Here’s a screenshot of the error:

image

I would recommend not adding a custom hook, but instead extending Controller, and passing it to CacheProvider. This will enhance your controller with whatever additional methods you want. (There are a bunch of downsides to creating ‘function hooks’)