这篇文章我们分析TypeDoc中的Component装饰器。
让我们退后一步,首先了解什么是 TypeScript 中的装饰器。
A Decorator 是一种特殊类型的声明,可以附加到类声明、方法、访问器、属性或参数。装饰器使用@表达式的形式,其中表达式必须计算为一个函数,该函数将在运行时调用,并包含有关装饰声明的信息。 - 来源。
例如,给定装饰器@sealed,我们可以将密封函数编写如下:
function sealed(target) { // do something with 'target' ... }
让我们从 TypeScript 文档中挑选一个简单易懂的示例来了解如何使用类装饰器。
@sealed class BugReport { type = "report"; title: string; constructor(t: string) { this.title = t; } }
这里@sealed是一个类装饰器,应用在类声明之上。这个@sealed是一个在运行时应用的装饰器。
如果你想防止对BugReport类进行任何修改,你可以定义密封函数如下:
function sealed(constructor: Function) { Object.seal(constructor); Object.seal(constructor.prototype); }
当执行 @sealed 时,它将密封构造函数及其原型,因此将防止在运行时通过访问 BugReport.prototype 或通过在 BugReport 本身上定义属性来向此类添加或删除任何进一步的功能 -来源
有了这些知识,我们现在准备了解 TypeDoc 代码库中的 @Component 装饰器。
@Component 装饰器是从 lib/utils/components.ts 导入的
这是一个装饰器工厂,它返回一个在运行时执行的箭头函数。您可以在 TS 文档中阅读有关装饰器工厂的更多信息。
export function Component(options: ComponentOptions) { // _context is ClassDecoratorContext, but that then requires a public constructor // which Application does not have. return (target: Function, _context: unknown) => { const proto = target.prototype; if (!(proto instanceof AbstractComponent)) { throw new Error( "The `Component` decorator can only be used with a subclass of `AbstractComponent`.", ); } if (options.childClass) { if (!(proto instanceof ChildableComponent)) { throw new Error( "The `Component` decorator accepts the parameter `childClass` only when used with a subclass of `ChildableComponent`.", ); } childMappings.push({ host: proto, child: options.childClass, }); } const name = options.name; if (name) { proto.componentName = name; } // If not marked internal, and if we are a subclass of another component T's declared // childClass, then register ourselves as a _defaultComponents of T. const internal = !!options.internal; if (name && !internal) { for (const childMapping of childMappings) { if (!(proto instanceof childMapping.child)) { continue; } const host = childMapping.host; host["_defaultComponents"] = host["_defaultComponents"] || {}; host["_defaultComponents"][name] = target as any; break; } } }; }
这个组件装饰器中发生了很多事情,我们不要试图理解所有内容,而是选择我们可以推断出的简单内容。
此检查用于在实例不受支持的情况下引发错误。
2. proto.componentName
proto.componentName 根据传递给装饰器的名称进行更新。在本例中,名称设置为“application”。
3.子映射
// If not marked internal, and if we are a subclass of // another component T's declared // childClass, then register ourselves as a _defaultComponents of T. const internal = !!options.internal; if (name && !internal) { for (const childMapping of childMappings) { if (!(proto instanceof childMapping.child)) { continue; } const host = childMapping.host; host["_defaultComponents"] = host["_defaultComponents"] || {}; host["_defaultComponents"][name] = target as any; break; } }
childMapping.host 进行了一些更新
在 Think Throo,我们的使命是教授开源项目中使用的高级代码库架构概念。
通过在 Next.js/React 中练习高级架构概念,提高您的编码技能,学习最佳实践并构建生产级项目。
我们是开源的 — https://github.com/thinkthroo/thinkthroo (请给我们一颗星!)
我们还提供网络开发和技术写作服务。请通过 [email protected] 联系我们了解更多信息!
https://github.com/TypeStrong/typedoc/blob/master/src/lib/application.ts#L100
https://www.typescriptlang.org/docs/handbook/decorators.html
https://github.com/TypeStrong/typedoc/blob/master/src/lib/utils/component.ts#L39
https://www.typescriptlang.org/docs/handbook/decorators.html#decorator-factories
免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。
Copyright© 2022 湘ICP备2022001581号-3