I'm @nyaomaru, a frontend engineer exploring new possibilities with Jev ๐ธ (I'm also curious about "Decisions API" from OpenAI)
Recently, I was looking into the TypeScript Compiler API and asking a pretty specific question
Can reusable type guards preserve not only the AST node type, but also a narrowed child property?
We want to know two things: Is this a CallExpression? Is its expression an Identifier?
And honestly, if this check appears only once, I would probably leave it exactly like this.
Now suppose the same AST shape appears in several places: a visitor filter find another transformation another lint rule
Since TypeScript v5.5, simple functions can often infer a type predicate automatically.
So if we want the extracted predicate to preserve both facts, we have to describe the refined type explicitly.
It would be nice if we could compose the checks and let the type follow them. ๐ธ
within the composed narrowing chain, checks one property on the parent already narrowed by ts.isCallExpression and preserves the checked child type.
Check the child once at runtime, then carry that same fact back to the parent type.
The Compiler API is simply a really good stress test for it because AST code contains this pattern everywhere.
The Compiler API is just an advanced example of a more generic composition problem.
Another thing I wanted to avoid was wrapping TypeScript's existing predicates unnecessarily.
I like keeping this separate from refineKey because absence is runtime behavior, not just a TypeScript annotation.
Suppose we want a function-like declaration whose: body exists body is a block first statement exists first statement is a return statement
We did not prove that every property from some wider key domain passed the same test.
That's why the refinement helpers intentionally work with one concrete key or index.
