You Stay Classy, San Diego

So, there are classes in Javascript.  I know- not really, but practically, by using new es6 features, you can create a class that looks and works similarly to any other classical language.  I know- it doesn’t work the same ‘under the hood’- it’s really still just using JS’s existing prototype chain and assignment mechanic (right?).  But it does make it easier for those of us familiar with classical inheritance to quickly create some useful components.

We work in Typescript on one project.  It’s great because it provides a transpiler- allowing us to use the latest and greatest es6 features, then dumbing them down for the real world (i.e.: some older browsers).  When I found myself copying a method among multiple components in an Angular 2 application, my first instinct was to create a service those components could share access to, then move the method there.  But as I thought about it, I realized creating a base class might be just as easy, and a fun alternative to explore.

And so was born the Utilities class.  As a super simple example, I had a ‘cancel’ method on most components.  A user clicks the ‘cancel’ button and the app jumps back to the previous view and shows a notification.  We had a notification component already, and using the ‘Location’ class provided by Angular would make the navigation aspect easy.

The class has a bit of Angular magic- the Injectable decorator (though I’m not sure if it’s absolutely necessary here- it seems like the common practice is to put it on any class that’s not explicitly a component).  Ignore that for now:

@Injectable()
export class Utilities {
  constructor(
    public location: Location,
    public notificationService: NotificationService
  ) {}
}

Looks just like any other JS class so far- except the parameter passed to the constructor.  There’s some Typescript leaking in, but really we’re just instantiating the Location class (provided by Angular) and our NotificationService class (custom- shows a little notification modal).

Then, later in the component, comes the actual method:

cancel(msg?: string, type?: string): void {
  this.location.back();
  this.notificationService.showNotification({
    timer: 2000,
    message: msg || 'Update Canceled',
    type: type || 'warning'
  });
}

More TS sprinkled in there- it’s pretty cool stuff!  A question mark after a parameter means it is optional.  The identifier after the colon is the type (‘string’ in this case- but you can really get wild with this aspect).  Parameters in JS are generally pretty flexible- but this enforces a bit of structure and most editors will have some kind of intellesense going when you use the method that will show you exactly what you can pass to the function.  You can also use TS to define what the function will return (‘void’ in this case).  Note that none of this is necessary to the code working- it’s just useful to a developer and their team- and generally leads to more structured, easy to reason about, code.

Those familiar with es6 are probably laughing at me right now.  There’s at least one more cool refactoring I could make.  Now we can pass default arguments to function parameters.  So, instead of

cancel(msg?: string, type?: string)

We could do

cancel(msg = 'Update Canceled', type = 'warning')

Eliminating the need for the ‘or’ (||) operator in the object passed to the showNotification method.  When the cancel method is called, if there is a parameter passed in the first position, it will be set to ‘msg’- if not, it will pass the default ‘Update Canceled’ string (same with type).  Very cool!

We went down a bit of a rabbit hole there, but to finish off the inheritance aspect- now we just need to make sure the class/component that’s going to use this as a base ‘extends’ it and call the ‘super’ method:

export class UserEditComponent extends Utilities {
  constructor(
    public location: Location,
    public notificationService, NotificationService
  ) {
    super(location, notificationService);
  }
}

The first part is simple.  The ‘extends’ keyword lets your new class have access to the parent class methods (I’m betting it just assigns your new object to the same prototype ‘under the hood’, though I’m currently too busy/lazy to dig in).  But there is still a bit of work.  In the constructor, you have to make a ‘super’ call and pass along any necessary parameters (those you included in your parent class constructor).  Super calls the parent’s constructor function- necessary to provide this access.

But that’s it!  In my UserEditComponent class I now have access to the ‘cancel’ method.  I’ve been using VS Code lately (great editor!)- the code completion will even pick up that method.  So when I start typing and I get to the ‘dot’ in my call, any method on UserEditComponent or Utilities will show as an option.  The call to the parent class method is as easy as:

this.cancel(//optional msg and type parameters);

Pretty cool stuff.  And again- I think most of this is possible just using traditional JS prototypal inheritance syntax, but having another option is definitely useful.  One caution would be to simply remember that this is not actual classical inheritance.  I think there are some ‘gotchas’ that can happen if you do anything too complex without remembering that it’s all prototypes ‘under the hood’.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s