ts-morph
ts-morph copied to clipboard
CallExpression.addTypeArgument crashes if the CallExpression's expression is a PropertyAccessExpression
Describe the bug
Version: 13.0.2
addTypeArgument() only seems to work for simple call expressions of the form foo()
, but not forms like this.foo()
.
To Reproduce
Consider this source file:
function foo<T>(_param: T): void {
}
export class Test {
public foo<T>(_param: T): void {
}
public bar(): void {
this.foo({});
new Test().foo({});
foo({});
}
}
And this program:
import * as AST from "ts-morph";
const project = new AST.Project();
const sourceFile = project.addSourceFileAtPath("./CallExprAddTypeArgument.ts");
sourceFile.getDescendantsOfKind(AST.SyntaxKind.CallExpression).forEach(callExpr => {
callExpr.addTypeArgument("object");
});
We see the following crash for this.foo({})
and new Test().foo({})
, while it works as expected for foo({})
.../node_modules/@ts-morph/common/dist/ts-morph-common.js:473
throw new InvalidOperationError(typeof errorMessage === "string" ? errorMessage : errorMessage());
^
Error: A child of the kind Identifier was expected.
at Object.throwIfNullOrUndefined (.../node_modules/@ts-morph/common/dist/ts-morph-common.js:473:19)
at CallExpression.getFirstChildByKindOrThrow (.../node_modules/ts-morph/dist/ts-morph.js:3754:30)
at CallExpression.insertTypeArguments (.../node_modules/ts-morph/dist/ts-morph.js:10006:41)
at CallExpression.addTypeArguments (.../node_modules/ts-morph/dist/ts-morph.js:9995:25)
at CallExpression.addTypeArgument (.../node_modules/ts-morph/dist/ts-morph.js:9992:25)
...
It appears as though insertTypeArguments assumes it will have an identifier as a direct child. In reality, it could be an expressioned node and thus the identifier is not a direct child.
Expected behavior
The type argument should be added without crashing for all three of the example call expressions.
From some quick testing, I believe something like this in TypeArgumentedNode.ts
addresses the issue, though I'm unsure if there are any more complicating factors.
insertTypeArguments(index: number, argumentTexts: ReadonlyArray<string>) {
...
if (typeArguments.length === 0) {
const expression = Node.hasExpression(this) ? this.getExpression() : undefined;
const nodeWithIdentifier = Node.isPropertyAccessExpression(expression) ? expression : this;
const identifier = nodeWithIdentifier.getFirstChildByKindOrThrow(SyntaxKind.Identifier);
insertIntoParentTextRange({
...
I experience the same issue. Have you come around this?