From c142420b370e579976b0b2ab43c41e713e93d0de Mon Sep 17 00:00:00 2001 From: avallete Date: Tue, 7 Jan 2025 11:55:22 +0900 Subject: [PATCH] fix(types): type result for throwOnError responses When using throwOnError(), the response type is now more strictly typed: - Data is guaranteed to be non-null - Error field is removed from response type - Response type is controlled by generic ThrowOnError boolean parameter Fixes #563 --- src/PostgrestBuilder.ts | 46 ++++++++++++++++++++++++++++++++++------- test/index.test-d.ts | 45 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 83 insertions(+), 8 deletions(-) diff --git a/src/PostgrestBuilder.ts b/src/PostgrestBuilder.ts index 621785c9..05a9f0d3 100644 --- a/src/PostgrestBuilder.ts +++ b/src/PostgrestBuilder.ts @@ -1,11 +1,22 @@ // @ts-ignore import nodeFetch from '@supabase/node-fetch' -import type { Fetch, PostgrestSingleResponse } from './types' +import type { Fetch } from './types' import PostgrestError from './PostgrestError' -export default abstract class PostgrestBuilder - implements PromiseLike> +export default abstract class PostgrestBuilder + implements + PromiseLike< + ThrowOnError extends true + ? { data: Result; count: number | null; status: number; statusText: string } + : { + data: Result | null + error: PostgrestError | null + count: number | null + status: number + statusText: string + } + > { protected method: 'GET' | 'HEAD' | 'POST' | 'PATCH' | 'DELETE' protected url: URL @@ -42,9 +53,9 @@ export default abstract class PostgrestBuilder * * {@link https://github.com/supabase/supabase-js/issues/92} */ - throwOnError(): this { + throwOnError(): PostgrestBuilder { this.shouldThrowOnError = true - return this + return this as PostgrestBuilder } /** @@ -56,9 +67,30 @@ export default abstract class PostgrestBuilder return this } - then, TResult2 = never>( + then< + TResult1 = ThrowOnError extends true + ? { data: Result; count: number | null; status: number; statusText: string } + : { + data: Result | null + error: PostgrestError | null + count: number | null + status: number + statusText: string + }, + TResult2 = never + >( onfulfilled?: - | ((value: PostgrestSingleResponse) => TResult1 | PromiseLike) + | (( + value: ThrowOnError extends true + ? { data: Result; count: number | null; status: number; statusText: string } + : { + data: Result | null + error: PostgrestError | null + count: number | null + status: number + statusText: string + } + ) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null diff --git a/test/index.test-d.ts b/test/index.test-d.ts index 50a2444d..bf016d40 100644 --- a/test/index.test-d.ts +++ b/test/index.test-d.ts @@ -1,5 +1,6 @@ +import { TypeEqual } from 'ts-expect' import { expectError, expectType } from 'tsd' -import { PostgrestClient } from '../src/index' +import { PostgrestClient, PostgrestError } from '../src/index' import { Prettify } from '../src/types' import { Database, Json } from './types' @@ -211,3 +212,45 @@ const postgrest = new PostgrestClient(REST_URL) expectType(y) expectType(z) } + +// Should have nullable data and error field +{ + const result = await postgrest.from('users').select('username, messages(id, message)').limit(1) + let expected: + | { + username: string + messages: { + id: number + message: string | null + }[] + }[] + | null + const { data } = result + const { error } = result + expectType>(true) + let err: PostgrestError | null + expectType>(true) +} + +// Should have non nullable data and no error fields if throwOnError is added +{ + const result = await postgrest + .from('users') + .select('username, messages(id, message)') + .limit(1) + .throwOnError() + const { data } = result + // @ts-expect-error error property does not exist when using throwOnError() + const { error } = result + let expected: + | { + username: string + messages: { + id: number + message: string | null + }[] + }[] + expectType>(true) + // just here so our variable isn't unused + error +}