Types on conditional joins

Hey everyone!
I'm struggling with maintaining type safety when adding conditional joins in Drizzle.
I have a function that builds a query with conditional joins based on parameters. Depending on the parameters, I might need to join different tables. However, TypeScript isn't correctly inferring the return type, and I have to cast it, which defeats the purpose of type safety.
Here's a simplified version of my code:

type JoinOptions = Partial<Record<'withFoo' | 'withBar', true>>;

type BaseFields = ReturnType<typeof getTableColumnAliases<typeof baseTable>>;
type FooFields = ReturnType<typeof getTableColumnAliases<typeof fooTable>>;
type BarFields = ReturnType<typeof getTableColumnAliases<typeof barTable>>;

type MyQuerySelection<T extends JoinOptions> = {
base: BaseFields;
} & (T['withFoo'] extends true ? { foo: FooFields } : {}) &
(T['withBar'] extends true ? { bar: BarFields } : {});

export function buildMyQuery<T extends JoinOptions>({
params,
joins = {} as T,
}: {
params: MyQueryParams;
joins?: T;
}) {
const selectClauses = {
base: getTableColumnAliases(baseTable),
...(joins.withFoo && { foo: getTableColumnAliases(fooTable) }),
...(joins.withBar && { bar: getTableColumnAliases(barTable) }),
};

let query = db.select(selectClauses).from(baseTable).$dynamic();

if (joins.withFoo) {
query = withFoo({ query, params });
}

if (joins.withBar) {
query = withBar({ query, params });
}

return query;
}

But even with conditional types, TypeScript doesn't infer the return type based on joins. I have to cast the return type, which isn't ideal.
Here's how I'm using the function:

const query = buildMyQuery({
params: myParams,
joins: { withFoo: true },
});

const results = await query.execute();

results.forEach((row) => {
console.log(row.foo?.someField); // Error: Property 'foo' does not exist
});

Has anyone faced this issue or have suggestions?
Thanks in advance!
Was this page helpful?