Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript decorators vs class inheritance

I am a bit cofused by typescript decorators and how they are explained. Supposedly they 'decorate' a class by associating metadata with it. I can't really seem to grasp the concept of how that metadata is then associated with a class's instance. Take the angular 2 example.

 @Component(
       {
          selector:...
       }
    ) 


    export class foo { ... }

Currently as I understand angular will instantiate the class foo and somehow associate the instance with the decorator's arguments so that it can provide services, directives, and templates. All of this seems to be able to also be implementable via class inheritance. If I have a Component class and make my component extend that class why can't angular then provide those arguments when it bootstraps in the way that react does with props, and completely get rid of decorators in this use scenario.

class Component { ... } //say this has members such as selector, services, directives, etc..

class Foo extends Component { ... }

then you would instantiate it, at bootstrap/runtime with this

new Foo(ElementName, Directives, Services, etc..)

With react this is technically what went on under the hood. You derived component and implemented its methods. If you need to pass information when instantiating, then you pass in the props object.

please enlighten me.

like image 484
Alan Avatar asked Jul 31 '16 19:07

Alan


2 Answers

This code surely looks similar:

import { Component } from '@angular/core';
export class AppComponent extends Component{ }

VS:

import { Component } from '@angular/core';
@Component()
export class AppComponent { }

You can do inheritance in JS in different ways - if you opt in for using the Class syntactic sugar and want to go with the extends syntax for implementing inheritance then you are locked in with single inheritance - so each class can only inherit one other class.

With @Decorators it is possible to attach multiple behaviours to a class, thus creating multiple inheritance not unlike with mixins. As Günter Zöchbauer pointed out, decorators are much easier to be evaluated statically, while inheritance has to be evaluated at runtime (i.e. if the compiler wants to know what kind of behaviours a specific child class has).

I look at @Decorators as composition - as they are basically functions, I view them the same as higher-order functions, so it is like doing something like that, but more readable:

import { Component } from '@functionalComponent/core';
let myComponent = function() { return {hello: 'world'}}
let AppComponent = Component(myComponent())

Do not forget that Class is in essence pure JS object, created/instantiated by a constructor function.

import { Component } from '@constructedComponent/core';
let MyComponent = function() {this.hello ='world'}
let AppComponent = new Component(new MyComponent)

Or go even 'lower' and imagine it as pure objects:

import { Component } from '@objectComponent/core';
let MyComponent = {this.hello ='world'}
let AppComponent = Component.augment(MyComponent)

Generally, the prototypal and functional natures of JS are very powerful and allow for mixing in behavior through calling functions and altering objects. That changes when you switch to the Class syntax - at this point you should stick to OOP design principle known as Composition over inheritance and the decorators are a neat way to express composition with a nice-to-read syntax:

Difference between the Composite Pattern and Decorator Pattern?

From Wikipedia:

Decorator use can be more efficient than subclassing, because an objects behavior can be augmented without instantiating an entirely new object.

like image 120
Petrunov Avatar answered Nov 06 '22 23:11

Petrunov


As far as I know the main reason is to make it easy to evaluate statically. With inheritance you would need to execute TS (or transpiled JS) code to get the information.

Evaluating this metadata statically allows tools to use it for autocompletion and all kind of lint checks in the template as well as building designers and other tools that make it easier to build Angular applications.

Also the offline template compiler utilizes this metadata.

like image 23
Günter Zöchbauer Avatar answered Nov 06 '22 23:11

Günter Zöchbauer