In this article, we analyse the Component decorator in TypeDoc.
Let’s take a step back and first understand what’s a decorator in TypeScript.
A Decorator is a special kind of declaration that can be attached to a class declaration, method, accessor, property, or parameter. Decorators use the form @expression, where expression must evaluate to a function that will be called at runtime with information about the decorated declaration. — Source.
For example, given the decorator @sealed we might write the sealed function as follows:
function sealed(target) { // do something with 'target' ... }
Let’s pick a simple and easy to understand example from TypeScript documentation about how to use class decorator.
@sealed class BugReport { type = "report"; title: string; constructor(t: string) { this.title = t; } }
Here @sealed is a class decorator applied just above the class declaration. This @sealed is a decorator that is applied at run time.
If you want to prevent any modifications to the class BugReport, you could define sealed function as below:
function sealed(constructor: Function) { Object.seal(constructor); Object.seal(constructor.prototype); }
When @sealed is executed, it will seal both the constructor and its prototype, and will therefore prevent any further functionality from being added to or removed from this class during runtime by accessing BugReport.prototype or by defining properties on BugReport itself — Source
With this knowledge, we are now prepared to understand the @Component decorator in TypeDoc code base.
@Component decorator is imported from lib/utils/components.ts
This is a decorator factory that returns an arrow function that is executed at run time. You can read more about decorator factory in TS docs.
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; } } }; }
There is a lot happening in this Component decorator, instead of trying to understand it all, let’s pick up on the easy ones we can deduce.
This check is used to throw an error in case the instance is not supported.
2. proto.componentName
proto.componentName is updated based on name passed to the decorator. In this case, the name is set to “application”.
3. childMappings
// 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; } }
There are some updates made to childMapping.host
At Think Throo, we are on a mission to teach the advanced codebase architectural concepts used in open-source projects.
10x your coding skills by practising advanced architectural concepts in Next.js/React, learn the best practices and build production-grade projects.
We are open source — https://github.com/thinkthroo/thinkthroo (Do give us a star!)
We also provide web development and technical writing services. Reach out to us at [email protected] to learn more!
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
Disclaimer: All resources provided are partly from the Internet. If there is any infringement of your copyright or other rights and interests, please explain the detailed reasons and provide proof of copyright or rights and interests and then send it to the email: [email protected] We will handle it for you as soon as possible.
Copyright© 2022 湘ICP备2022001581号-3