From 8e171f54c435215d9677ccb7f8ea8f6f89fac04a Mon Sep 17 00:00:00 2001 From: Mark Fulton Date: Fri, 19 Jul 2024 11:18:57 -0500 Subject: [PATCH] Use KyRequest and KyResponse types in errors (#610) * feat: additional json convenience methods - introduces `KyRequest` which, like `KyResponse`, adds `json()` convenience method for extracting JSON with an expected TypeScript type - update API `Request`/`Response` usages to expose `KyRequest`/`KyResponse` to `ky` consumers so that they may use the `json()` convenience method in more scenarios (`HTTPError`, `TimeoutError`, and hooks) Refs: #584 * fix unnecessary assertion * docs(readme): mention `.json()` TS improvements --- readme.md | 1 + source/errors/HTTPError.ts | 6 ++++-- source/errors/TimeoutError.ts | 4 +++- source/index.ts | 1 + source/types/hooks.ts | 10 +++++----- source/types/request.ts | 4 ++++ test/hooks.ts | 2 +- 7 files changed, 19 insertions(+), 9 deletions(-) diff --git a/readme.md b/readme.md index 9826868a..ffff3aaf 100644 --- a/readme.md +++ b/readme.md @@ -71,6 +71,7 @@ It's just a tiny file with no dependencies. - URL prefix option - Instances with custom defaults - Hooks +- TypeScript niceties (e.g. `.json()` resolves to `unknown`, not `any`; `.json()` can be used too) ## Install diff --git a/source/errors/HTTPError.ts b/source/errors/HTTPError.ts index 6f9f2dae..5630828f 100644 --- a/source/errors/HTTPError.ts +++ b/source/errors/HTTPError.ts @@ -1,9 +1,11 @@ import type {NormalizedOptions} from '../types/options.js'; +import type {KyRequest} from '../types/request.js'; +import type {KyResponse} from '../types/response.js'; // eslint-lint-disable-next-line @typescript-eslint/naming-convention export class HTTPError extends Error { - public response: Response; - public request: Request; + public response: KyResponse; + public request: KyRequest; public options: NormalizedOptions; constructor(response: Response, request: Request, options: NormalizedOptions) { diff --git a/source/errors/TimeoutError.ts b/source/errors/TimeoutError.ts index d3526918..c99c9f9d 100644 --- a/source/errors/TimeoutError.ts +++ b/source/errors/TimeoutError.ts @@ -1,5 +1,7 @@ +import type {KyRequest} from '../types/request.js'; + export class TimeoutError extends Error { - public request: Request; + public request: KyRequest; constructor(request: Request) { super(`Request timed out: ${request.method} ${request.url}`); diff --git a/source/index.ts b/source/index.ts index 58010280..c466c917 100644 --- a/source/index.ts +++ b/source/index.ts @@ -48,6 +48,7 @@ export type { } from './types/hooks.js'; export type {ResponsePromise} from './types/ResponsePromise.js'; +export type {KyRequest} from './types/request.js'; export type {KyResponse} from './types/response.js'; export {HTTPError} from './errors/HTTPError.js'; export {TimeoutError} from './errors/TimeoutError.js'; diff --git a/source/types/hooks.ts b/source/types/hooks.ts index 90abcd39..b8070a62 100644 --- a/source/types/hooks.ts +++ b/source/types/hooks.ts @@ -1,14 +1,14 @@ import {type stop} from '../core/constants.js'; -import {type HTTPError} from '../index.js'; +import type {KyRequest, KyResponse, HTTPError} from '../index.js'; import type {NormalizedOptions} from './options.js'; export type BeforeRequestHook = ( - request: Request, + request: KyRequest, options: NormalizedOptions ) => Request | Response | void | Promise; export type BeforeRetryState = { - request: Request; + request: KyRequest; options: NormalizedOptions; error: Error; retryCount: number; @@ -16,9 +16,9 @@ export type BeforeRetryState = { export type BeforeRetryHook = (options: BeforeRetryState) => typeof stop | void | Promise; export type AfterResponseHook = ( - request: Request, + request: KyRequest, options: NormalizedOptions, - response: Response + response: KyResponse ) => Response | void | Promise; export type BeforeErrorHook = (error: HTTPError) => HTTPError | Promise; diff --git a/source/types/request.ts b/source/types/request.ts index 17e31086..28ea6444 100644 --- a/source/types/request.ts +++ b/source/types/request.ts @@ -59,3 +59,7 @@ type UndiciRequestInit = { type CombinedRequestInit = globalThis.RequestInit & UndiciRequestInit; export type RequestInitRegistry = {[K in keyof CombinedRequestInit]-?: true}; + +export type KyRequest = { + json: () => Promise; +} & Request; diff --git a/test/hooks.ts b/test/hooks.ts index 5e01e922..7d3c909e 100644 --- a/test/hooks.ts +++ b/test/hooks.ts @@ -652,7 +652,7 @@ test('beforeError can return promise which resolves to HTTPError', async t => { beforeError: [ async (error: HTTPError) => { const {response} = error; - const body = await response.json() as {reason: string}; + const body = await response.json<{reason: string}>(); if (response?.body) { error.name = 'GitHubError';