How to add assignment property to existing object literal expression in typescript compiler api?

Total
1
Shares

I want to add bar: true to x object using typescript AST.

This code cerates the bar: true:

 factory.createPropertyAssignment(
   factory.createIdentifier("bar"),
   factory.createTrue()
 );

I know I need to return this function in order to add it to AST. if I do so then the problem is the code will override the foo: true.

Any ideas how to add bar: true without lose the foo: true?

The code:

import * as ts from "typescript";

const code = `
const x = {
  foo: true
})
`;

const node = ts.createSourceFile("x.ts", code, ts.ScriptTarget.Latest);

const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });

export const add = (context) => (rootNode) => {
  function visit(node) {
    const { factory } = context;

    // if (node.kind === ts.SyntaxKind.ObjectLiteralExpression) {
    //   return factory.createPropertyAssignment(
    //     factory.createIdentifier("bar"),
    //     factory.createTrue()
    //   );
    // }

    return ts.visitEachChild(node, visit, context);
  }

  return ts.visitNode(rootNode, visit);
};

const result = ts.transform(node, [add]);

// console.log({ result });
const transformedSourceFile = result.transformed[0];

const out = printer.printFile(transformedSourceFile);

console.log({ out });

codesandbox.io


Solution

If you’re doing this in typescript, node.properties is readonly. The type-safe way is to use the factory.update*() methods when you want to mutate the current node and return it:

export const add: ts.TransformerFactory<ts.SourceFile> = (context) => (rootNode) => {
    function visit(node: ts.Node): ts.VisitResult<ts.Node> {
        const { factory } = context;

        // using the provided typeguard to narrow the node kind
        if (ts.isObjectLiteralExpression(node)) {
            return factory.updateObjectLiteralExpression(node, [
                    // include the existing properties
                    ...node.properties,
                    // add your generated property
                    factory.createPropertyAssignment(
                        factory.createIdentifier("bar"),
                        factory.createTrue()
                    )
                ]
            );
        }
        return ts.visitEachChild(node, visit, context);
    }

    return ts.visitNode(rootNode, visit);
};
Leave a Reply

Your email address will not be published. Required fields are marked *