如何使用TypeScript编译器API向TypeScript类添加新属性?

问题描述

我尝试将新属性添加到我的awesome.model.ts文件中。

原始内容如下:

import { TagInterface,TagUIFieldsInterface } from './tag.interface';

export class Tag implements TagInterface {
  readonly api_endpoint = '/tag';
  id: ID;
  name: string;

  fields: FieldContainerInterface<TagUIFieldsInterface> = {
    // ...
  };

  init(data?: any): TagInterface {
    // ...
  }
}

我想在color_code: string;属性行之后添加一个属性name。看起来像这样:

import { TagInterface,TagUIFieldsInterface } from './tag.interface';

export class Tag implements TagInterface {
  readonly api_endpoint = '/tag';
  id: ID;
  name: string;
  color_code: string;

  fields: FieldContainerInterface<TagUIFieldsInterface> = {
    // ...
  };

  init(data?: any): TagInterface {
    // ...
  }
}

在Schematics规则函数中,我尝试了此操作,但被卡住了:

export function model(_options: Schema,_fields?: Field[]): Rule {
  return (tree: Tree,_context: SchematicContext) => {
    // ...

    if (tree.exists(file)) {
      // read the file content and convert it to ts.Node[]
      const text = tree.read(file) ?? '';
      let sourceText = text.toString('utf-8');
      const sourceFile = ts.createSourceFile(file,sourceText,ts.ScriptTarget.Latest,true);
      const nodes = getSourceNodes(sourceFile);

      updateModelFields(file,nodes,_options);

      return;
    }
}

这是updateModelFields()函数

export function updateModelFields(file: string,nodes: ts.Node[],options: Schema) {
  // find field deFinitions
  let propertyNodes: ts.Node[] = nodes.filter(n => n.kind === ts.SyntaxKind.PropertyDeclaration) || [];

  // create new property declaration
  const propertyDeclaration = ts.factory.createPropertyDeclaration(
    undefined,undefined,'color_code',ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),undefined
  );

  // add propertyDeclaration to nodes
  // ??
}

我尝试了几种添加属性声明的方法,但总是失败。

当我尝试添加splice()函数时,它说:

Error: Debug Failure. False expression: Node must have a real position for this operation

有什么想法或最佳做法吗?

解决方法

通常,如果使用转换API,它将与food函数一起使用,然后使用ts.transform将属性添加到类中。最终转换后的AST之后,您可以使用打印机(factory.updateClassDeclaration)将其打印为字符串。

也就是说,转换API不是为此目的而设计的,它是将TS代码转换为JS的,因此在修改现有的TypeScript文件方面不是很好。例如,如果您转换AST然后将其打印出来,则会丢失格式信息,并且可能会破坏现有注释。

由于这个原因,我建议改用文本更改API(请参阅ts.createPrinter)(这是用于快速修复的方法),或更简单地说,只需将属性文本插入字符串中的正确位置即可直。您可以根据周围的节点位置确定要插入的位置。例如:

SourceFile#update

或者,您可能只想使用ts-morph为您处理此问题,因为quite easy会使用它向类中插入属性。