Skip to content

Conversation

@JLHwung
Copy link
Contributor

@JLHwung JLHwung commented Aug 21, 2025

Q                       A
Fixed Issues?
Patch: Bug Fix?
Major: Breaking Change?
Minor: New Feature?
Tests Added + Pass? Yes
Documentation PR Link
Any Dependency Changes?
License MIT

This PR improves the typings of NodePath modification APIs in @babel/traverse: Namely insertBefore, insertAfter, unshiftContainer, pushContainer and replaceWithMultiple. Previously the return value them were general NodePaths, this PR introduced a few typescript mixins such that TS can infer the specific return value from the provided modification nodes. The listKey of unshiftContainer and pushContainer is also narrowed to those key whose value is an array of AST nodes.

Thanks to the improved typings, we can remove a few redundant type casts from their usage.

@JLHwung JLHwung added the PR: Polish (next major) 💅 A type of pull request used for our changelog categories for next major release label Aug 21, 2025
@babel-bot
Copy link
Collaborator

babel-bot commented Aug 21, 2025

Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/59858

return this.replaceExpressionWithStatements(nodes);
} else if (Array.isArray(this.container)) {
return _containerInsertBefore.call(this, nodes);
return _containerInsertBefore.call(this, nodes) as NodePaths<Nodes>;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new type casts in the implementation of these API are a bit unfortunate. Helps are welcome.

}

export function _verifyNodeList<N extends t.Node>(
export function _verifyNodeList<N extends t.Node | null>(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _verifyNodeList currently does not accept null in nodes. However, I think we should eventually accept null, because null represents a hole / empty pattern in ArrayExpression#elements or ArrayPattern#elements. The API should not have prevent users from adding them to the elements.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Aug 21, 2025

Open in StackBlitz

commit: ba172dc

Copy link
Member

@nicolo-ribaudo nicolo-ribaudo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks very nice. I left a suggestion to try removing the type casts, but even if it's not possible I very much prefer casting in @babel/traverse than in its callers.

(parentPath.isExportDefaultDeclaration() && this.isDeclaration())
) {
return parentPath.insertBefore(nodes);
return parentPath.insertBefore(nodes) as NodePaths<Nodes>;
Copy link
Member

@nicolo-ribaudo nicolo-ribaudo Aug 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this work instead of the type case?

Suggested change
return parentPath.insertBefore(nodes) as NodePaths<Nodes>;
return parentPath.insertBefore<Nodes>(nodes);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately not. The issue as I perceive here is that _verifyNodeList returns t.Node[] and TS considers verified nodes as a different subtype of NodeOrNodeList<t.Node> than Nodes so type casting is required.

There are also two unsound type casting in the insertAfter implementation, we might consider if we want to fix that in Babel 8.

return this.replaceExpressionWithStatements(nodes);
} else if (Array.isArray(this.container)) {
return _containerInsertBefore.call(this, nodes);
return _containerInsertBefore.call(this, nodes) as NodePaths<Nodes>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this

Suggested change
return _containerInsertBefore.call(this, nodes) as NodePaths<Nodes>;
return _containerInsertBefore<Nodes>.call(this, nodes);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately TS does not allow property access after TSInstantiateExpressions.

@JLHwung JLHwung merged commit 22493b6 into babel:main Aug 22, 2025
86 of 87 checks passed
@JLHwung JLHwung deleted the improve-babel-traverse-typings branch August 22, 2025 20:50
This was referenced Nov 19, 2025
@github-actions github-actions bot added the outdated A closed issue/PR that is archived due to age. Recommended to make a new issue label Nov 22, 2025
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Nov 22, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

outdated A closed issue/PR that is archived due to age. Recommended to make a new issue PR: Polish (next major) 💅 A type of pull request used for our changelog categories for next major release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants