diff --git a/README.md b/README.md index c6f775f..823d86c 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,13 @@ const { data } = await tf.patch('https://api.example.com/users/123', { title: 'Director of Engineering' }) +// PATCH request +const { data } = await tf.patch('https://api.example.com/users/123', { + body: { + title: 'Director of Engineering' + } +}) + // DELETE request const { data, response } = await tf.delete('https://api.example.com/users/123') ``` @@ -355,4 +362,4 @@ MIT License - see [LICENSE](LICENSE) for details. --- -**TypedFetch**: Because life's too short for complex HTTP clients. 🚀 \ No newline at end of file +**TypedFetch**: Because life's too short for complex HTTP clients. 🚀 diff --git a/src/core/resource-builder.ts b/src/core/resource-builder.ts index 6706f37..0b7aa64 100644 --- a/src/core/resource-builder.ts +++ b/src/core/resource-builder.ts @@ -70,8 +70,8 @@ export interface ResourceBuilderOptions { } interface ResourceRequester { - request(method: string, url: string, init?: RequestInit, bodySample?: unknown): Promise<{ - data: any + request(method: string, url: string, init?: RequestInit, bodySample?: unknown): Promise<{ + data: T response: Response }> } @@ -85,10 +85,21 @@ export function createResource( const normalizedBase = normalizePath(basePath, options.trailingSlash) const resource: Record = {} - for (const [name, config] of Object.entries(definition)) { - resource[name] = async ( - args: ResourceCallArgs, Record> = {} - ) => { + for (const name of Object.keys(definition) as Array) { + type Config = TDefinition[typeof name] + type BodyType = Config extends ResourceMethodConfig ? TBody : never + type ParamsType = Config extends ResourceMethodConfig + ? TParams + : Record + type QueryType = Config extends ResourceMethodConfig + ? TQuery + : Record + type ResponseType = Config extends ResourceMethodConfig + ? TResponse + : unknown + const config = definition[name] as Config + + resource[name as string] = async (args: ResourceCallArgs = {}) => { const method = (config.method || 'GET').toUpperCase() const path = joinPaths(normalizedBase, config.path, options.trailingSlash) const resolvedPath = applyParams(path, args.params) @@ -100,12 +111,12 @@ export function createResource( const finalUrl = `${resolvedPath}${query}` const shouldUseJson = config.json ?? true - const serializer = config.serializeBody + const serializer = config.serializeBody as ((body: BodyType) => BodyInit | undefined) | undefined const hasBody = args.body !== undefined const prepared = hasBody ? serializer - ? { bodyInit: serializer(args.body), sample: args.body } - : prepareBodyPayload(args.body, { json: shouldUseJson }) + ? { bodyInit: serializer(args.body as BodyType), sample: args.body } + : prepareBodyPayload(args.body as BodyType, { json: shouldUseJson }) : undefined const init: RequestInit = { @@ -120,7 +131,7 @@ export function createResource( init.body = prepared?.bodyInit ?? null } - const result = await requester.request( + const result = await requester.request( method, finalUrl, init, @@ -132,7 +143,7 @@ export function createResource( response: result.response } } - return result as { data: unknown; response: Response } + return result } } diff --git a/src/core/typed-fetch.ts b/src/core/typed-fetch.ts index d423a0b..e13a278 100644 --- a/src/core/typed-fetch.ts +++ b/src/core/typed-fetch.ts @@ -91,7 +91,7 @@ export class RevolutionaryTypedFetch { const mergedConfig = mergeConfig(this.config, config) - return new RevolutionaryTypedFetch(mergedConfig) + return new RevolutionaryTypedFetch(mergedConfig) } // REAL runtime type tracking @@ -237,7 +237,7 @@ export class RevolutionaryTypedFetch { return createResource(this, path, definition, options) } - + private resolveUrl(url: string): string { // Use baseURL from config or instance const baseURL = this.config.request.baseURL || this.baseURL @@ -1182,4 +1182,4 @@ export class RevolutionaryTypedFetch