如何使用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 {
// ...
}
}

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

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 {
// ...
}
}

在我的原理图规则函数中,我尝试过这个,但我被卡住了:

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',
undefined,
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,则这将与ts.transform函数一起使用,然后使用factory.updateClassDeclaration将属性添加到类中。一旦获得了最终转换的AST,就可以使用打印机(ts.createPrinter(将其打印为字符串。

也就是说,转换API并不是为这个目的而设计的——它的目的是将TS代码转换为JS-and,因此它不适合修改现有的TypeScript文件。例如,如果您转换AST然后将其打印出来,您将丢失格式信息,并且它可能会践踏现有的注释。

出于这个原因,我建议使用文本更改API(请参见SourceFile#update(——这是用于快速修复的方法——或者更简单地说,直接将属性文本插入字符串中的正确位置。您可以根据周围节点的位置来确定插入位置。例如:

const classDec = sourceFile.statements.find(ts.isClassDeclaration)!;
const nameProp = classDec.members
    .find(c => ts.isPropertyDeclaration(c) && c.name.getText(sourceFile) === "name")!;
// Assumes that the name property node does not have any trailing comments...
// You can use ts.getTrailingCommentRanges to figure that out and use
// the last comment end position instead of `nameProp.end`
sourceText = sourceText.substring(0, nameProp.end)
    + "n  color_code: string;"
    + sourceText.substring(nameProp.end);

或者,你可能只想使用ts变形来处理这个问题,因为使用它可以很容易地将属性插入到类中

最新更新