Repository navigation
Description
TypeScript 4.7 variance annotations (interface A<in T>, <out T>, <in out T>) parse as ERROR in the bundled tree-sitter-typescript v0.23.2 (f975a62). This affects both src/extraction/wasm/tree-sitter-{typescript,tsx}.wasm and the kernel's crates.io tree-sitter-typescript = "0.23".
Decision (revised 2026-11-03): carry a patch, in two PRs.
- PR A, variance annotations: fix(typescript): parse variance annotations (
<in T>,<out T>,<in out T>) colbymchenry/codegraph#3226 (open). It vendors v0.23.2 with a regeneratedtype_parameterrule for the wasm and the kernel. Effect goes from 239 to 185 files with errors, Zod from 4 to 0, and VS Code and Excalidraw parse unchanged. Known limit: a type or tsx tag literally namedout/inafter an expression<(<out>x,<out>…</out>). - PR B, generic call signatures on their own line (bug: anonymous generic call signatures fail to parse when separated only by line breaks tree-sitter/tree-sitter-typescript#335): not opened yet. The first scanner attempt broke
name\n<T>()methods (a review finding), so it needs a redesign that fires only after a complete type. Most of Effect's whole-file failures (Schema.ts,Stream.ts,Channel.ts) wait on this one.
Close this issue when both have merged, or when upstream ships fixes and the patch is dropped.
Upstream PRs to watch
- feat: support variance annotations on type parameters (TypeScript 4.7) tree-sitter/tree-sitter-typescript#361: adds a named
(variance)node - feat: support variance annotations on type parameters tree-sitter/tree-sitter-typescript#364: adds anonymous
in/outtokens
Both PRs as written regress out used as a type-parameter name (<out>, <out = X>, <out, T>, tsx <out,>() =>), which master parses. brajevicm/tree-sitter-typescript@9fcaa13 carries a fix for colbymchenry#364. When one of them merges, check that it includes that fix before bumping. Related links:
- Bug report: Type-parameter variance annotations (in / out / in out, TS 4.7) are not in the grammar — every use fails to parse tree-sitter/tree-sitter-typescript#370
- Maintainer question: Who maintains tree-sitter-typescript now? tree-sitter/tree-sitter#6091 (the repo has had no commit since 2025-01-30)
Impact (measured 2026-11-03; corrected)
The first measurement only counted ERROR nodes that start on a variance line, and found 377 lines in Effect. That was wrong. In large files, accumulated errors make tree-sitter give up and wrap the whole file in one ERROR starting at line 1, which the first count did not attribute.
Corrected method: for each Effect (7a87ff9) file with an ERROR span of at least 50 lines, bisect to the first statement that breaks parsing. 18 files account for 156,109 of the 165,462 lines inside ERROR. This assigns each file to its first cause only; a file may have more.
| first cause | files | lines inside ERROR | upstream |
|---|---|---|---|
generic call signature on a new line with no ; ({ (x): A\n <A>(self: A): A }) |
11 | 111,434 | tree-sitter/tree-sitter-typescript#335 (open, no PR) |
variance annotations (<out A>) |
6 | 42,405 | colbymchenry#361 / colbymchenry#364 |
optional parenthesized tuple element ([(readonly [number?])?]) |
1 | 2,270 | not reported |
The variance files include Effect's core Schema.ts (19,231 lines), Stream.ts (12,300) and Channel.ts (9,254). These files index as almost nothing. In minimal repros all three bugs stay local (1-2 lines). The whole-file blow-up comes only from many errors accumulating in one big file.
Zod is only lightly affected: 4 files, 5 lines.
When upstream merges
- Bump the grammar for both the wasm and the kernel, keeping the two at parity.
- Add regression tests: variance declarations give no ERROR,
<out>is still accepted as a parameter name, and Effect'sSchema.ts/Stream.ts/Channel.tsno longer parse as a whole-file ERROR. - Close this issue.
If neither PR moves, a fallback plan exists: vendor colbymchenry#364 plus 9fcaa13, following the kotlin pattern in docs/grammars/.
Activity