Although the title may seem strange, I hope to clarify with an example.
I have a collection of predefined SQL queries stored in an object structured like this:
const queries = {
getProductById: {
params: { id: 'number' },
sql: `select * from product where id = :id`
},
getCustomerById: {
params: { id: 'number' },
sql: `select * from customer where id = :id`
}
// ... etc ...
};
export { queries };
When referencing these queries in another file, I can simply import
the queries
object and access the query by its key, which is validated by the TypeScript compiler:
// compiles without issues
db.executeQuery(queries.getProductById, { id: 42 });
// compiler error, because "nonexistentQuery" is not defined
db.executeQuery(queries.nonexistentQuery, { id: 7 });
Now, my goal is to enhance type safety for the queries
variable. My initial approach was to create an interface with an index signature:
interface IQueryList {
[queryName: string]: {
params?: { [paramName: string]: string };
sql: string;
};
}
However, applying this type annotation to my queries
variable led to loss of type safety when accessing a specific query:
const queries: IQueryList = {
getProductById: {
params: { id: 'number' },
sql: `select * from product where id = :id`
}
};
// no compiler error, as "queries" now has an index signature
db.executeQuery(queries.nonexistentQuery, { id: 12 });
Is there a way to maintain both type safety while defining a query, and protection against referencing an undefined query within the queries
object?
One solution could involve assigning a unique type annotation to each query, like so:
interface IQuery {
params?: { [paramName: string]: string };
sql: string;
}
const getProductQuery: IQuery = {
params: { id: 'number' },
sql: `select * from product where id = :id`
};
const queries = {
getProductQuery
};
// compiler error, since "nonexistentQuery" is not present
db.executeQuery(queries.nonexistentQuery, { id: 12 });
Although this method works, it requires individual tagging for each query, which may be cumbersome. It also does not prevent mistakenly formatted objects from being added to the final queries
collection.