开发工具【免费下载链接】ts-morphTypeScript Compiler API wrapper for static analysis and programmatic code changes.项目地址https://gitcode.com/gh_mirrors/ts/ts-morph点击查看免费下载本篇文章以 ts-morph 仓库中的 classes 官方文档 为主线系统讲解ClassDeclaration类声明的获取、命名、增删改查、继承关系分析、成员操作与接口提取等完整能力。读完本文你将能够用 ts-morph 以类型安全的方式对类声明进行静态分析与程序化代码变更并理解这些 API 在源码中的底层实现。获取类声明类声明可以从源文件SourceFile、命名空间Namespace或函数体中获取。ts-morph 将这些容器统一封装为语句容器getClasses()等查询方法定义在 StatementedNode.ts 中其实现是对getStatements()结果按节点类型过滤const classes sourceFile.getClasses(); const class1 sourceFile.getClass(Class1); const firstClassWithConstructor sourceFile.getClass(c c.getConstructors().length 0);三种典型用法对应getClasses()返回全部ClassDeclaration[]getClass(Class1)按名称精确匹配返回ClassDeclaration | undefinedgetClass(predicate)传入 find 函数做条件查询返回第一个满足条件的声明或undefined。类似地还有getClassOrThrow()它会在找不到时抛出带有明确错误信息的异常。从源码看getClass最终委托给getNodeByNameOrFindFunction(this.getClasses(), nameOrFindFunction)完成按名或按函数的查找。注意查询到的类声明以及下文的成员、属性等都支持传字符串名字或传断言函数两种参数形态这是 ts-morph 的一贯设计。名称Name允许匿名类类声明可能没有名字例如export default class {}这种匿名默认导出export default class { // etc... }因此ClassDeclaration上的getName()与getNameNode()都返回可空类型nullable。在做依赖类名才能执行的操作如查找派生类、提取接口时使用默认名称时源码中也会显式处理getName() null的情形——例如 ClassDeclaration.ts 中getDefaultExtractedName会依次回退到类名、源文件名去扩展名并清洗非法字符。添加与插入Add / Insert通过addClass()、addClasses()、insertClass()、insertClasses()可以在源文件、命名空间或函数体内添加或插入类声明const classDeclaration sourceFile.addClass({ name: ClassName, });从 StatementedNode.ts 的实现可以看出addClasses等价于在语句数组末尾插入insertClasses(index, ...)则支持指定子节点索引位置插入逻辑统一走_insertChildren并由structurePrinterFactory.forClassDeclaration(...)打印出最终文本。传入的结构体支持完整的ClassDeclarationStructure字段name、extends、implements、ctors、methods、properties、getAccessors、setAccessors、staticBlocks、typeParameters、decorators、docs等这些成员会在结构体设置阶段被逐一展开写入。移除Remove调用.remove()即可从源文件中删除该声明ts-morph 会同步处理好格式化与前后空行classDeclaration.remove();Extends 表达式getExtends()返回ExpressionWithTypeArguments | undefined即extends子句的类型节点可带类型实参const extendsExpression classDeclaration.getExtends();设置 extends 表达式支持字符串或WriterFunctionclassDeclaration.setExtends(BaseClass);移除 extendsclassDeclaration.removeExtends();在底层实现ClassLikeDeclarationBase.ts中setExtends会优先定位已有的extendsHeritageClause 做原位替换若不存在则在implements子句之前或类体{之前插入extends text而removeExtends本质是移除 extends 子句中的第一个类型节点。此外还有getExtendsOrThrow()供必须存在的场景使用。Implements 表达式getImplements()返回ExpressionWithTypeArguments[]即所有implements的类型节点数组const implementsExpressions classDeclaration.getImplements();添加或插入 implements 表达式支持单个字符串、字符串数组classDeclaration.addImplements(Named); classDeclaration.addImplements([Named, Aged]); classDeclaration.insertImplements(1, Named); classDeclaration.insertImplements(1, [Named, Aged]);按索引或按节点移除某个表达式classDeclaration.removeImplements(0); // index classDeclaration.removeImplements(classDeclaration.getImplements()[0]); // nodeinsertImplements的index指的是 implements 表达式列表中的位置从 0 开始。基类型Base TypesgetBaseTypes()返回Type[]它基于类型检查器解析extends与implements声明的类型层面的父类型const baseTypes classDeclaration.getBaseTypes(); // returns: Type[]源码实现ClassLikeDeclarationBase.ts就是this.getType().getBaseTypes()。文档特别强调当类可能继承自 mixin多个基类型交叉合并时应优先使用getBaseTypes()因为 type 层面能返回完整的父类型集合而不只是单个基类。基类Base ClassgetBaseClass()返回ClassDeclaration | undefined它只关心真正的类const baseClass classDeclaration.getBaseClass(); // returns: ClassDeclaration | undefined实现上ClassLikeDeclarationBase.ts该方法先把基类型按交叉类型展开收集其 symbol 的声明然后只保留ClassDeclaration类型的声明当恰好只有一个类声明时返回它否则返回undefined。因此若基类可能是 mixin请使用.getBaseTypes()而不是.getBaseClass()。派生类Derived ClassesgetDerivedClasses()返回所有继承自当前类的类声明含间接派生避免循环引用const derivedClasses classDeclaration.getDerivedClasses();其实现ClassLikeDeclarationBase.ts先通过getImmediateDerivedClasses找到直接派生类对类名做findReferencesAsNodes()引用查找过滤出位于extendsHeritageClause 中、且父级为ClassDeclaration的节点然后 BFS 式地逐层扩展所有间接派生类同时用classes.indexOf(derivedClass) -1防止循环继承造成死循环。注意由于依赖findReferencesAsNodes此方法要求类名节点存在匿名类无法使用。构造函数ConstructorgetConstructors()返回类中的构造函数声明数组const constructors classDeclaration.getConstructors();关键语义源码见 ClassLikeDeclarationBase.ts 与getAllMembers的过滤逻辑ambient环境声明上下文返回所有构造函数包括重载签名非 ambient 上下文仅返回实现构造函数overload 签名会被过滤掉。添加或插入构造函数使用addConstructor()、addConstructors()、insertConstructor()、insertConstructors()const ctor classDeclaration.addConstructor({ /* options like parameters may go here */ });构造函数结构体支持parameters、scope、returnType、docs、decorators等字段。例如classDeclaration.addConstructor({ parameters: [{ name: value, type: number, scope: Scope.Public }], });set()方法在设置ctors结构时会先getConstructors().forEach(c c.remove())清空再重新添加ClassDeclaration.ts实现整体替换。方法Methods获取实例方法支持按名或按 find 函数const instanceMethods classDeclaration.getInstanceMethods(); const myMethod classDeclaration.getInstanceMethod(myMethod); const firstMethodWith2Params classDeclaration.getInstanceMethod(m m.getParameters().length 2);获取静态方法const staticMethods classDeclaration.getStaticMethods(); const myStaticMethod classDeclaration.getStaticMethod(myMethod); const firstStaticMethodWith2Params classDeclaration.getStaticMethod(m m.getParameters().length 2);添加 / 插入const method classDeclaration.addMethod({ isStatic: true, name: myMethod, returnType: string });insertMethods(index, ...)、insertMethod、addMethod、addMethods四件套齐备。MethodDeclarationStructure支持isStatic、name、parameters、returnType、typeParameters、statements函数体、scope、isAbstract、isAsync、isGenerator、decorators、docs等字段。移除method.remove();属性Properties获取实例属性——包含参数属性parameter properties即构造函数的public/private/readonly参数提升为的属性const instanceProperties classDeclaration.getInstanceProperties(); const myProperty classDeclaration.getInstanceProperty(myProperty); const myStringProperty classDeclaration.getInstanceProperty(p Node.isPropertyDeclaration(p) p.getType().getText() string);获取静态属性const staticProperties classDeclaration.getStaticProperties(); const myStaticProperty classDeclaration.getStaticProperty(myStaticProperty); const myStaticStringProperty classDeclaration.getStaticProperty(p Node.isPropertyDeclaration(p) p.getType().getText() string);添加 / 插入添加或插入属性const property classDeclaration.addProperty({ isStatic: true, name: prop, type: string, });添加 get 访问器const getAccessor classDeclaration.addGetAccessor({ name: someNumber, returnType: number, statements: [return 5;], });添加 set 访问器const setAccessor classDeclaration.addSetAccessor({ name: someNumber, parameters: [{ name: value, type: number }], statements: [_someNumber value;], });以上均有对应的insertGetAccessors()/insertGetAccessor/addGetAccessors/addGetAccessor与insertSetAccessors()/insertSetAccessor/addSetAccessors/addSetAccessor变体定义见 ClassLikeDeclarationBase.ts。移除propertyDeclaration.remove();获取成员Get membersgetMembers()返回全部成员不区分静态或实例包含构造函数与静态块ClassStaticBlockDeclarationconst allMembers classDeclaration.getMembers();getInstanceMembers()返回实例成员包含参数属性不含构造函数const instanceMembers classDeclaration.getInstanceMembers();getStaticMembers()返回静态成员含静态块不含构造函数与参数属性const staticMembers classDeclaration.getStaticMembers();底层实现值得留意getMembers()会过滤掉无函数体的重载方法/构造函数ambient 上下文除外getInstanceMembers()通过getMembersWithParameterProperties()把实现构造函数中的参数属性提升为成员ClassLikeDeclarationBase.ts。此外还有getMember(name)、getMemberOrThrow()、getMembersWithComments()含注释类元素等更细粒度的 API。提取接口Extracting an InterfaceextractInterface()可从类中提取出等价的接口声明结构体InterfaceDeclarationStructure用于重构类 → 接口或生成类型约束// the passed in name is optional and defaults to the class name const interfaceStructure classDeclaration.extractInterface(I${classDeclaration.getName()});提取静态部分的接口结构体const interfaceStructure classDeclaration.extractStaticInterface(${classDeclaration.getName()}Static);从 ClassDeclaration.ts 的实现看提取规则为extractInterface仅收集public的实例成员——包括构造函数的 public 参数属性转为PropertySignatureStructure、public 属性、public 访问器get/set 合并为只读或可写属性签名、public 方法重载展开为MethodSignatureStructure并保留类的 JSDoc 与类型参数extractStaticInterface收集public 静态成员并把构造函数转为ConstructSignaturereturnType指向实例接口名参数属性的 JSDoc 注释会从构造函数的param标签中提取并迁移到对应属性签名上名字缺省时依次回退传入名 → 类名 → 源文件基础名清洗非法字符。抽象Abstract类的节点方法、访问器等成员可以为抽象。AbstractableNodemixinAbstractableNode.ts为类及类成员提供了统一能力method.isAbstract(); // returns: boolean获取抽象关键字节点method.getAbstractKeyword(); // returns: node | undefined设置是否为抽象method.setIsAbstract(true); // set as abstract method.setIsAbstract(false); // set as not abstract实现上isAbstract()即getAbstractKeyword() ! nullgetAbstractKeyword()查找abstract修饰符setIsAbstract通过toggleModifier(abstract, isAbstract)增删修饰符并同步处理格式化。构造函数 / 方法 / 属性更深入的能力文档提示ConstructorDeclaration、MethodDeclaration、PropertyDeclaration各自实现了函数类声明FunctionLikeDeclaration上的通用能力并叠加了各自专属能力ConstructorsConstructorDeclaration除具备函数式声明的参数、返回类型、重载、JSDoc、装饰器能力外还带有scope作用域public / protected / private支持isOverload()判断是否重载签名、isImplementation()判断是否实现体、isParameterProperty()判断参数属性等MethodsMethodDeclaration支持isStatic、isAbstract、isAsync、isGenerator、作用域与重载等PropertiesPropertyDeclaration支持isStatic、isReadonly、hasQuestionToken可选属性、isAbstract、作用域、getType()等。这些成员的具体方法非常丰富实践中可通过 IDE 的自动补全auto-complete直接探索全部能力。访问器互相查找Get / Set Accessors如果存在对应的访问器get 访问器可以反向找到配对的 set 访问器const setAccessor getAccessor.getSetAccessor();set 访问器也可以反向找到配对的 get 访问器const getAccessor setAccessor.getGetAccessor();这为读写属性对的联动分析如检查某个属性是否只读、是否存在非对称访问器提供了便捷入口。小结结合本文与源码可以确认ts-morph 对类声明的支持是全方位的查询getClasses/getClass、增删addClass/insertClass/remove、继承分析getExtends/getImplements/getBaseTypes/getBaseClass/getDerivedClasses、成员操作方法、属性、访问器、构造函数、静态块、抽象修饰以及接口提取extractInterface/extractStaticInterface。这些 API 的绝大多数能力集中在 ClassDeclaration.ts 与 ClassLikeDeclarationBase.ts 中对应的行为验证可参考 classDeclarationTests.ts。如果你想系统掌握 ts-morph 中ExpressionWithTypeArguments表达式与类型实参、接口声明等相邻概念可继续阅读 expressions 与 interfaces 文档。赞分享开发工具【免费下载链接】ts-morphTypeScript Compiler API wrapper for static analysis and programmatic code changes.项目地址https://gitcode.com/gh_mirrors/ts/ts-morph点击查看免费下载相关推荐ts-morph 修饰符Modifiers操作完全指南读取、查询与切换类成员与声明的关键字ts morph 修饰符Modifiers操作完全指南读取、查询与切换类成员与声明的关键字 本文基于 ts morph 官方文档 docs/details开发工具ts-morph 接口声明完全指南检索、增删改查、继承分析与实现定位ts morph 接口声明完全指南检索、增删改查、继承分析与实现定位 本指南基于 ts morph 源码库中 docs/details/interfaces.开发工具jynew MOD 模块设计四种加载通道、描述文件规范与运行时启动全解析jynew MOD 模块设计四种加载通道、描述文件规范与运行时启动全解析 本文基于《jynew MOD模块设计》设计文档展开结合 jyx2/Assets/S开发工具上一篇JetBrains IDE试用期重置终极指南如何轻松获得30天免费使用时间下一篇RePKG深度解析Wallpaper Engine资源解包与TEX格式转换的专业工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考