unjs / ofetch

😱 A better fetch API. Works on node, browser and workers.
MIT License
3.63k stars 119 forks source link

replace type of body in fetch options #290

Closed mbadr2200 closed 10 months ago

mbadr2200 commented 10 months ago

Environment

node : v16.20.1

Reproduction

.

Describe the bug

it's not a bug but i want to make a composable like useFetch in nuxt with type-safe IntelliSense When I extend the Fetch options I get intellesense with this type body?: ((BodyInit | Record<string, any> | null) & Product) | undefined and a lot of properties that I don't need so I try to omit the body from the fetch options to get the property I need only but I got error on the $fetch function

Argument of type 'Options<R, M>' is not assignable to parameter of type 'FetchOptions<any> | undefined'.
  Type 'Options<R, M>' is not assignable to type 'FetchOptions<any>'.
    Types of property 'body' are incompatible.
      Type '(Body<R, M> extends never ? undefined : Body<R, M>) | undefined' is not assignable to type 'BodyInit | Record<string, any> | null | undefined'.
        Type 'Body<R, M> extends never ? undefined : Body<R, M>' is not assignable to type 'BodyInit | Record<string, any> | null | undefined'.
          Type 'Body<R, M> | undefined' is not assignable to type 'BodyInit | Record<string, any> | null | undefined'.
            Type 'Body<R, M>' is not assignable to type 'BodyInit | Record<string, any> | null | undefined'.
              Type 'unknown' is not assignable to type 'BodyInit | Record<string, any> | null | undefined'.
                Type 'Body<R, M>' is not assignable to type 'URLSearchParams'.
                  Type 'unknown' is not assignable to type 'URLSearchParams'.
                    Type 'Body<R, M> extends never ? undefined : Body<R, M>' is not assignable to type 'URLSearchParams'.
                      Type 'Body<R, M> | undefined' is not assignable to type 'URLSearchParams'.
                        Type 'undefined' is not assignable to type 'URLSearchParams'.ts(2345)

this is my code below

import type { Api } from "~/ERP-Configs/types/api"
import { FetchOptions, $fetch } from "ohmyfetch";

type Request = keyof Api;

type Method<R extends Request> = keyof Api[R];

type Body<R extends Request, M extends Method<R>> = Api[R][M] extends {
    BODY: infer B;
} ? B : never;

type Return<R extends Request, M extends Method<R>> = Api[R][M] extends {
    BODY: any; RETURN: infer P
}
    ? P
    : Api[R][M] extends { BODY: any }
    ? void
    : Api[R][M];

type Options<R extends Request, M extends Method<R>> = Omit<FetchOptions,'body'> & {
    method: M;
    body?: Body<R, M> extends never ? undefined : Body<R, M>;
}

const useApi = <R extends keyof Api, M extends Method<R>>(
    request: R,
    options: Options<R, M>
): Promise<Return<R, M>> => {
    return $fetch(request, options)
};

export default useApi;

Package.json:

{
  "name": "nuxt-app",
  "private": true,
  "type": "module",
  "scripts": {
    "build": "nuxt build",
    "dev": "nuxt dev",
    "generate": "nuxt generate",
    "preview": "nuxt preview",
    "postinstall": "nuxt prepare"
  },
  "devDependencies": {
    "@nuxt/devtools": "latest",
    "@nuxt/image": "^1.0.0-rc.1",
    "@nuxtjs/google-fonts": "^3.0.2",
    "@types/node": "^18.16.19",
    "@vueuse/core": "^10.3.0",
    "@vueuse/nuxt": "^10.3.0",
    "nuxt": "^3.6.5",
    "nuxt-icon": "^0.4.2",
    "nuxt-typed-router": "^3.2.6",
    "prettier": "^3.0.0",
    "prettier-plugin-tailwindcss": "^0.4.1"
  },
  "dependencies": {
    "@formkit/icons": "^0.17.5",
    "@formkit/nuxt": "^0.17.5",
    "@formkit/themes": "^0.17.5",
    "@headlessui/vue": "^1.7.14",
    "@pinia/nuxt": "^0.4.11",
    "@tabler/icons-vue": "^2.25.0",
    "autoprefixer": "^10.4.14",
    "axios": "^1.4.0",
    "conventional-changelog-conventionalcommits": "^6.1.0",
    "libphonenumber-js": "^1.10.39",
    "lodash": "^4.17.21",
    "lodash.debounce": "^4.0.8",
    "ohmyfetch": "^0.4.21",
    "pinia": "^2.1.6",
    "postcss": "^8.4.25",
    "primevue": "^3.32.0",
    "tailwindcss": "^3.3.2",
    "vue-tel-input": "^8.1.3",
    "vue-toastification": "^2.0.0-rc.5"
  },
  "version": "1.2.0"
}

I would appreciate any help

Additional context

No response

Logs

No response

pi0 commented 10 months ago

@mbadr2200 ohmyfetch is deprecated. can you please try upgrading to latest ofetch?

mbadr2200 commented 10 months ago

i changed the body to this and it worked

type Options<R extends Request, M extends Method<R>> = Omit<FetchOptions,'body'> & {
    method: M;
    body?: Body<R,M> extends Record<string,any> ? Body<R,M> : never;
}
mbadr2200 commented 10 months ago

oh , i didn't know that , thank you

@mbadr2200 ohmyfetch is deprecated. can you please try upgrading to latest ofetch?