Actually, yes, it is. The way these libraries work, since the thing that is parsed is NOT just a plain string, in most cases it's impossible to have sql injection without doing some deliberately nasty stuff. That is, you can't just do this:
const query = `select foo from bar where zed = ${param}`; // forgot the sql tag
await runQuery(query);
In that case, the type of query is just string, but the `runQuery` method doesn't take strings, it takes a parsed query, so that wouldn't work.
After using the tagged template literal pattern for SQL queries exclusively for the past couple years, I can't say enough how awesome it is to use in practice. Libraries even let you do strong typing with TypeScript to define the expected structure of the result, e.g.
sql<MyExpectedReturnType>`select foo from bar where zed = ${param}`
No, it usually returns a parsed object. For example the gql tag in the apollo client libraries return a completely parsed query with all its various children and sub-objects.
Why wouldn’t it be? Do you think developers get inspired by this slick API and decide to write functions that talk directly to the database using unescaped interpolated strings? I doubt it.
After using the tagged template literal pattern for SQL queries exclusively for the past couple years, I can't say enough how awesome it is to use in practice. Libraries even let you do strong typing with TypeScript to define the expected structure of the result, e.g.