TypeScript中如何获取类的命名空间?寻求可行实现方案
首先明确:TypeScript编译后,命名空间会被转化为嵌套的JavaScript对象,原生并没有直接获取完整命名空间路径的API,但结合你用TypeWriter生成DTO的场景,有几种靠谱的解决办法,按推荐程度排序:
1. 最优解:修改TypeWriter模板,生成时直接嵌入完整名称
既然你的DTO类是通过TypeWriter从C#生成的,那直接修改TypeWriter的模板,让它自动给每个类添加一个静态属性来存储完整的命名空间+类名,这是最可靠、最方便的方式——毕竟我们可以在生成阶段就拿到完整的命名信息,不需要运行时计算。
举个TypeWriter模板的修改示例:
// 你的TypeWriter类模板片段 namespace {{Namespace}} { export class {{Name}} { // 新增静态属性,直接注入完整命名空间+类名 public static readonly fullQualifiedName = "{{Namespace}}.{{Name}}"; // 原有属性生成逻辑 {{#Properties}} public {{Name}}: {{Type}}; {{/Properties}} // 原有构造函数或其他方法逻辑 {{#Constructor}} constructor({{Parameters}}) { {{#Properties}} this.{{Name}} = {{Name}}; {{/Properties}} } {{/Constructor}} } }
生成后的类就会自带fullQualifiedName静态属性,直接调用My.API.DTO.Something.fullQualifiedName就能得到你想要的My.API.DTO.Something,完全没有运行时的额外开销。
2. 手动实现运行时获取(无需第三方库)
如果因为某些原因不能修改TypeWriter模板,我们可以通过遍历对象链的方式,在运行时拼凑出完整名称。原理是TypeScript的命名空间编译后会变成嵌套的全局对象,比如My.API.DTO.Something实际上是window.My.API.DTO.Something(浏览器环境),我们可以从类本身出发,向上追溯它的所属对象链。
这里提供一个简单的实现函数:
function getFullClassName(cls: Function): string { let parts = [cls.name]; let currentObj = window; let target = cls; // 递归查找目标类所在的对象路径 function findParent(obj: any, path: string[]): string[] | null { for (const key in obj) { if (obj[key] === target) { return [key, ...path]; } // 如果当前属性是对象,递归查找 if (typeof obj[key] === 'object' && obj[key] !== null) { const result = findParent(obj[key], [key, ...path]); if (result) return result; } } return null; } const namespaceParts = findParent(currentObj, []); if (namespaceParts) { // 移除最后一个(因为最后一个是类名本身,已经在parts里了) namespaceParts.pop(); parts = [...namespaceParts, ...parts]; } return parts.join('.'); } // 使用示例 const fullName = getFullClassName(My.API.DTO.Something); console.log(fullName); // 输出 "My.API.DTO.Something"
注意:这个方法依赖全局对象(浏览器是window,Node.js是globalThis),如果你的代码是模块化的(比如用ES Modules),命名空间可能不会挂载到全局对象上,这种方法就不适用了。
3. 使用第三方库(比如ts-reflect)
如果需要更强大的反射能力,可以使用ts-reflect这样的第三方库,它能提供TypeScript类型的运行时信息,包括命名空间。不过使用它需要额外配置TypeScript编译器选项(比如开启emitDecoratorMetadata、experimentalDecorators),并且需要安装对应的依赖,相对重一些。
简单示例(需要先安装ts-reflect):
import { Type } from 'ts-reflect'; const type = Type.get<My.API.DTO.Something>(); const fullName = type.fullName; // 得到 "My.API.DTO.Something"
内容的提问来源于stack exchange,提问作者wonea

