ast-types
ast-types copied to clipboard
Cannot assign a Comment[] to node.comments.
This code:
function setComment(node: types.Node, comment: types.Comment) { node.comments = [comment]; }
Results in the following error: error TS2322: Type 'Comment[]' is not assignable to type 'CommentKind[]'. Type 'Comment' is not assignable to type 'CommentKind'. Property 'type' is missing in type 'Comment' but required in type 'CommentLine'.
Adding a "type" field to Comment doesn't help...
error TS2322: Type 'Comment[]' is not assignable to type 'CommentKind[]'. Type 'Comment' is not assignable to type 'CommentKind'. Type 'Comment' is not assignable to type 'CommentLine'. Types of property 'type' are incompatible. Type 'string' is not assignable to type '"CommentLine"'.
I believe the only resolution is to use CommentKind as the type in the function. Why are there both Command and CommentKind types? Wouldn't it be better if node.comments was of type Comment[]? Also, are the kinds exported at all by ast-types? I could only import them from 'ast-types/gen/kinds' which doesn't feel like an external api.
There are of course similar problems with Statement/StatementKind, Expression/ExpressionKind, etc. Any time code wants to directly mutate a node it cannot work with types of the base class and must always use kinds or leaf classes.
Please share how you're calling setComment, that's crucial information.
I don't know TypeScript so I'm not familiar with its errors, but it seems like it should be:
// I'm not sure if this is how you do it, but you get what I mean
import type * as kinds from "ast-types/gen/kinds";
function setComment(node: kinds.NodeKind, comment: kinds.CommentKind) {
node.comments = [comment];
}
Yes, using CommentKind works. But the *Kind types tend to make things more confusing. The developer needs to know that there's a second type hierarchy imported from a separate module which is kind of hidden in a place that doesn't look like part of a public api (ast-types/gen/kinds).
Due to the way the interfaces are generated I believe you can always assign a FooKind to a Foo, but the reverse is not true. So you can mostly write code using the normal namedTypes names as types (Statement, Comment, etc). It feels natural and obvious because the type names match node.type, etc. That works for passing things around and walking the structures.
Where this breaks down is whenever you need to declare a type somewhere in your program and then that type is assigned to a node's property. For example, if you wanted to write a utility function to set the comment on a node you might create the setComment() function above. But in this case you need to declare the argument as CommentKind instead of Comment and it is surprising.
My question wasn't how to make setComment() work. It was more along the lines of "why do we even have CommentKind in the first place?" I don't grasp the problem it is solving and it seems like there should be a better way to express these types. Or, if CommentKind is truly the best solution, then it really should be more visible as part of the public API, etc.
I'm still very new to this project, but yeah, it looks like kind types should be exposed in main.d.ts.