supabase/supabase-js

TypeScript - returned typed from query should reflect query filter

Opened this issue ยท 2 comments

Bug report

  • I confirm this is a bug with Supabase, not with my own application.
  • I confirm I have searched the Docs, GitHub Discussions, and Discord.

Describe the bug

Using query filters like .not("<column>", "is", null); does not produce types that correctly represents the returned data.

To Reproduce

Create a table posts

create table "public"."posts" (
    "id" bigint generated by default as identity not null,
    "content" text not null,
    "published_at" date
);

Generate types from the database schema.

supabase gen types typescript --local --schema public > functions/_shared/supabase.gen.ts

Write some TypeScript code to fetch posts.

import { createClient } from "@supabase/supabase-js";
import { Database } from "../_shared/supabase.gen";

const getPublishedPosts = async () => {
  const supabase = createClient<Database>("supabaseUrl", "supabaseAnonKey");

  const result = await supabase
    .from("posts")
    .select("*")
    .not("published", "is", null);

  if (result.error) {
    throw result.error;
  }

  const data = result.data;
};

Expected behavior

data should be of type

const data: {
    content: string;
    id: number;
    published_at: string; // ๐Ÿ‘ˆ string, not string | null
}[]

since we filtered published_at on NOT NULL in the query.

Actual behavior

data is of type

const data: {
    content: string;
    id: number;
    published_at: string | null;
}[]

System information

supabase --version: 2.23.4
node --version: v22.15.0

  "devDependencies": {
    "typescript": "5.8.3",
    "@supabase/supabase-js": "2.49.8"
  },

Types generated using the supabase CLI, are as per the schema of the table.

The create table DDL specified in the issue has "published_at" date. By default, postgres columns are nullable, unless you specify not null. With published_at as nullable, the type generated would be string | null.

since we filtered published_at on NOT NULL in the query.

Specifying not("published", "is", null) in the query does not change the type of the data returned. The data type for published_at would still be string | null as per the generated types for the table.


Edit: ORMs return the types from the schema. Parsing the query to identify if a type should be different is unnecessary overhead, and also opens up various other cases to be handled (casting for example).

I understand the technical aspect of it, I just think that it is a bad developer experience.

When writing .not("published", "is", null) all returned rows have non-null values for published_at, right? I believe the TypeScript typing system should reflect that.