Skip to content

Generic helper with constrained table set rejects string column refs (ReferenceExpression invariance?) #1669

@briandastous

Description

@briandastous

Versions

  • Kysely: 0.28.9
  • TypeScript: 5.9.3
  • Node: (not relevant)

Repro

  1. npm i kysely typescript
  2. Create tsconfig.json:
  {
    "compilerOptions": {
      "target": "ES2022",
      "module": "NodeNext",
      "moduleResolution": "NodeNext",
      "strict": true,
      "noEmit": true,
      "types": []
    }
  }
  1. Create repro.ts:
  import type { SelectQueryBuilder } from "kysely";

  interface DB {
    person: { id: number; name: string };
    pet: { id: number; owner_id: number };
  }

  // Attempt at a reusable helper that requires the "person" table to be present.
  function wherePersonHasName<DBT extends DB, TB extends keyof DBT, O>(
    qb: SelectQueryBuilder<DBT, "person" | TB, O>,
  ): SelectQueryBuilder<DBT, "person" | TB, O> {
    // Expect this to be valid because "person" is explicitly included in TB.
    return qb.where("person.name", "=", "alice");
  }

  // Usage with a concrete builder that *does* include "person".
  declare const concreteQuery: SelectQueryBuilder<DB, "person" | "pet", { id: number }>;
  wherePersonHasName(concreteQuery);
  1. npx tsc -p tsconfig.json

Actual

TS2345: Argument of type 'string' is not assignable to parameter of type 'ReferenceExpression<DBT, TB | "person">'.

Expected

The helper should typecheck because "person" is explicitly included in TB and "person.name" is a valid column reference.

Notes

  • Inlining the same where("person.name", ...) at the call site compiles.
  • The failure appears related to SelectQueryBuilder being invariant in TB / ReferenceExpression in a generic context, which makes it hard to write reusable, type-safe query helpers without assertions or sql.ref.
  • This blocks DRY filters that require certain tables to be present.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingtypescriptRelated to Typescript

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions