If you’ve spent some time working with React, you might have stumbled upon React Query’s looks shockingly simple:
export function queryOptions(options: unknown) {
return options
}
However, the real magic lies in its
Typed Database Queries
Inspired by React Query’s approach, I put together a helper function that might be useful for people working outside of React: a straightforward way to create typed queries, for example, SQL queries.
export declare const queryParamsSymbol: unique symbol;
export declare const queryReturnSymbol: unique symbol;
export type Query<
TParams extends Record<string, any> = Record<string, any>,
TReturn extends Record<string, any> | undefined = undefined,
TStatement extends string = string,
> = {
statement: TStatement;
[queryParamsSymbol]: TParams;
[queryReturnSymbol]: TReturn;
};
export function query<
TParams extends Record<string, any> = Record<string, any>,
TReturn extends Record<string, any> | undefined = undefined,
TStatement extends string = string,
>(statement: TStatement): Query<TParams, TReturn> {
return { statement: statement } as Query<TParams, TReturn, TStatement>;
}
Similar to queryOptions(), the function itself is pretty dull: it takes a SQL statement, wraps it in an object of type Query, and returns it.
Here’s a quick example of how you’d call it:
const getUserById = query<{ id: number }, { name: string; email: string }>(
'SELECT name, email FROM users WHERE id = $id',
);
Notice how we pass two types as generic parameters. The first is the required query parameters — in this case, id. The second represents the query’s return type — name and email.
Under the hood, query() embeds those two types into the returned object, stashing them in queryParamsSymbol and queryReturnSymbol. These symbols are declared as .
SOCIAL SHARE CARD GENERATOR