Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

$Fetch.create parametter type #453

Open
benavern opened this issue Oct 9, 2024 · 1 comment
Open

$Fetch.create parametter type #453

benavern opened this issue Oct 9, 2024 · 1 comment
Labels
bug Something isn't working

Comments

@benavern
Copy link

benavern commented Oct 9, 2024

Environment

"nuxt": "^3.13.2"
"typescript": "^5.6.3",
"vue-tsc": "^2.1.6"

Reproduction

This is just a type bug that I have in my project, I found a solution that could / seems to fix the bug and wanted to discuss it here

Describe the bug

when using $fetch.create() with the first parameter (defaults: FetchOptions) explicitely defined in my code as of type FetchOptions<'json'> I see an error (pasted in the Log part of this issue)

Additional context

after trying a large number of solutions, I have found that in the $Fetch type definition, the create method ha no generic attached on the first argument.

interface $Fetch {
    <T = any, R extends ResponseType = "json">(request: FetchRequest, options?: FetchOptions<R>): Promise<MappedResponseType<R, T>>;
    raw<T = any, R extends ResponseType = "json">(request: FetchRequest, options?: FetchOptions<R>): Promise<FetchResponse<MappedResponseType<R, T>>>;
    native: Fetch;
-    create(defaults: FetchOptions, globalOptions?: CreateFetchOptions): $Fetch;
+    create(defaults: FetchOptions<R>, globalOptions?: CreateFetchOptions): $Fetch;
}

this simple change seems to fix my issue. I don't know it this is the right solution though...

Logs

Argument of type '{ responseType: "json"; baseURL: string; body?: RequestInit["body"] | Record<string, any>; ignoreResponseError?: boolean; params?: Record<string, any>; query?: Record<string, any>; ... 24 more ...; onResponseError?: MaybeArray<...> | undefined; }' is not assignable to parameter of type 'FetchOptions<ResponseType, any>'.
  Types of property 'retryDelay' are incompatible.
    Type 'number | ((context: FetchContext<any, "json">) => number) | undefined' is not assignable to type 'number | ((context: FetchContext<any, ResponseType>) => number) | undefined'.
      Type '(context: FetchContext<any, "json">) => number' is not assignable to type 'number | ((context: FetchContext<any, ResponseType>) => number) | undefined'.
        Type '(context: FetchContext<any, "json">) => number' is not assignable to type '(context: FetchContext<any, ResponseType>) => number'.
          Types of parameters 'context' and 'context' are incompatible.
            Type 'FetchContext<any, ResponseType>' is not assignable to type 'FetchContext<any, "json">'.
              Type 'ResponseType' is not assignable to type '"json"'.
                Type '"text"' is not assignable to type '"json"'.

Edit:
I tried this in my project: #371

This seams to fix my problem, but can't confirm as of now...

@benavern benavern added the bug Something isn't working label Oct 9, 2024
@benavern
Copy link
Author

benavern commented Oct 9, 2024

For more information, here is the code of the abstract class I have this issue in:

import type { $Fetch, FetchOptions } from 'ofetch';
import { $fetch } from 'ofetch';

export type RepositoryOptions = FetchOptions<'json'>;

export interface ApiResponseList<Item> {
    data: Item[],
    nbr: number,
    nb_pages: number,
}

export default abstract class AbstractRepository<ApiItem> {
    private _fetch: $Fetch;

    constructor(fetchOptions: RepositoryOptions & { baseURL: string }, applySecureOptions?: (options?: RepositoryOptions) => RepositoryOptions | undefined) {
        // Create the base fetch instance
        // @ts-ignore
        // @see: https://github.com/unjs/ofetch/issues/453
        this._fetch = $fetch.create({
            headers: {
                Accept: 'application/json',
                ...fetchOptions?.headers,
            },
            ...fetchOptions,
            responseType: 'json',
        });

        // Override the applySecureOptions method
        if (applySecureOptions) this.applySecureOptions = applySecureOptions;
    };

    // Should add all the usefull stuff in requests for authentificated api calls
    protected applySecureOptions(options?: RepositoryOptions): RepositoryOptions | undefined {
        return options;
    }

    // This is where the magic happens! The api call is made here, with all the data needed
    protected async call<FetchResponse = ApiItem>(url: string, options?: RepositoryOptions): Promise<FetchResponse> {
        return this._fetch(url, { method: 'GET', ...options });
    }
    
    // the same thing than the `call` method, but with `applySecureOptions` applied
    // <!> if you didn't provide a `applySecureOptions` this does exactly the same as the `fetch` method...
    protected async callSecure<FetchResponse = ApiItem>(url: string, options?: RepositoryOptions): Promise<FetchResponse> {
        const secureOptions = this.applySecureOptions(options);

        return this._fetch(url, { method: 'GET', ...secureOptions });
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant