taozhi8833998 / taozhi8833998/node-sql-parser
TypeScript types disagree with parser output: Select.having, ColumnRefItem.schema, Value.type (PostgreSQL)
@taozhi8833998 is already working on this.
Since May 7, 2026.
- Dominant language
- PEG.js
- Stars
- 1k
- Forks
- 244
- PR merge metrics
- No merged PRs in 30d
Description
Describe the bug
Three places in types.d.ts disagree with what the parser actually emits at runtime, all of which prevent discriminated-union narrowing on the AST in TypeScript:
- Select.having is declared any[] | null, but the parser emits a single Binary node (or null).
- ColumnRefItem omits a schema?: string field that the parser does emit for namespaced identifiers (schema_a.table.col).
- Value.type is declared as string rather than a literal-string union of the actual node-types the parser emits. This blocks node.type === '' narrowing on ExpressionValue because Value overlaps with every other discriminator.
Filing as one issue since they're related (all three force consumers walking the AST into shape coercion or hand-rolled type predicates).
Database Engine
PostgreSQL
To Reproduce
-
node-sql-parser version: 5.4.0
-
node version: tested on Node 22.22.0
Three runnable repros:
- Select.having shape — runtime is a Binary, type says any[]:
const { Parser } = require('node-sql-parser');
const ast = new Parser().astify(
'SELECT * FROM t GROUP BY t.id HAVING count(t.x) > 5',
{ database: 'PostgresQL' }
);
console.log('ast.type:', ast.type); // 'select' (confirms root is Select)
console.log('Array.isArray(having):', Array.isArray(ast.having)); // false
console.log('having.type:', ast.having.type); // 'binary_expr'
- column_ref carries a schema field that's not declared:
const { Parser } = require('node-sql-parser');
const ast = new Parser().astify(
'SELECT * FROM t WHERE actions.foo.bar = 1',
{ database: 'PostgresQL' }
);
console.log(JSON.stringify(ast.where.left, null, 2));
// Prints: { type: 'column_ref', schema: 'actions', table: 'foo', column: 'bar', ... }
// `ColumnRefItem` in types.d.ts declares only `table` and `column`.
- Value.type blocks narrowing — TypeScript-level repro:
import type { ExpressionValue } from 'node-sql-parser';
declare const node: ExpressionValue;
if (node.type === 'binary_expr') {
// tsc error: Property 'operator' does not exist on type 'Binary | Value'.
// Property 'operator' does not exist on type 'Value'.
const op: string = node.operator;
console.log(op);
}
Run with: npx tsc --noEmit --strict --target es2020 --moduleResolution node .ts
Expected behavior
types.d.ts should match the parser's runtime output. The parser is behaving correctly; the types drifted. Suggested type fixes:
- Select.having — currently any[] | null, should be Binary | null to match what the parser emits.
- ColumnRefItem — currently has no schema field, should declare schema?: string (mirrors BaseFrom.schema?, which is already declared and behaves the same way for FROM
items). - Value.type — currently string, should be a closed literal-string union of the types the parser actually emits. At minimum:
type: 'number' | 'bigint' | 'string' | 'single_quote_string'
| 'double_quote_string' | 'bool' | 'null' | 'date' | 'time'
| 'timestamp' | 'datetime' | 'hex_string' | 'bit_string';
No runtime changes needed — only types.d.ts.
Screenshots
N/A — repros above produce the evidence in stdout/tsc output.
Additional context
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.