Macroable
- Overview
- Installation
- CommonJS, ESM, and TypeScript Support
- Traditional Approach
- Using Macroable
- Adding IntelliSense
Overview
The @supercharge/macroable
package provides a base class allowing you to extend the class prototype in a declarative way. Extending the prototype allows you to add functions to an ES6 class in JavaScript or TypeScript from third party packages.
Installation
The @supercharge/macroable
package lives independently from the Supercharge framework. Using it in your application requires you to install it as a project dependency:
npm i @supercharge/macroable
You can use this package with every project even if it’s not build on Supercharge. Enjoy!
CommonJS, ESM, and TypeScript Support
The macroable package supports both module loaders: CommonJS and ESM (and also TypeScript). Import the Macroable
class in your projects like this:
// ESM and TypeScript
import { Macroable } from '@supercharge/macroable'
// CommonJS
const { Macroable } = require('@supercharge/macroable')
Traditional Approach
The typical approach extending a JavaScript class is applying a custom function to the class’ prototype. This adds the given function to the class and makes it callablel on class instances. Here’s how you would do it:
class User {
private firstname: string = 'Supercharge'
}
// in another file/package
User.prototype.greet = function () {
return `Hello ${this.firstname}!`
}
Using Macroable
The Macroable
class is a base class exposing methods to extends a class prototype in a declarative way. We call this declarative way "adding a macro". You may also determine whether a method is macro’ed to the class. Or you can remove all macros from a class.
Adding Macros
Add a macro to a class by extending the Macroable
class and calling the static Class.macro(name, method)
function:
import { Macroable } from '@supercharge/macroable'
class User extends Macroable {
private firstname: string = 'Supercharge'
}
// in another file/package
User.macro('hello', function () {
return `Hello ${this.firstname}!`
})
const user = new User()
user.hello()
// Hello Supercharge!
Has Macro
You may determine whether a function on a class was added as a macro using the hasMacro
method:
Macroable.hasMacro('method-name')
Here’s an example of checking whether a class’s method is a macro function:
import { Macroable } from '@supercharge/macroable'
class User extends Macroable {
greeting(): string {
return 'Hello World!'
}
}
User.macro('hello', function () {
return `Hello ${this.firstname}!`
})
User.hasMacro('hello')
// true
User.hasMacro('greeting')
// false -- because "greeting" was not macro’ed to the class
Deleting Macros
You can remove all macros from a class using the static flushMacros
method:
Macroable.flushMacros()
Notice: flushing all macros removes all added methods from the class prototype, entirely. All macros are gone from the point you’re calling the flush method.
import { Macroable } from '@supercharge/macroable'
class User extends Macroable {
private firstname: string = 'Supercharge'
}
User.macro('hello', function () {
return `Hello ${this.firstname}!`
})
User.flushMacros()
const user = new User()
user.hello
// undefined
Adding IntelliSense
A shortcoming for macros are IntelliSense in your editor. During development you want your editor to show autocompletions while typing. Dynamically adding methods to a class using macros won’t add type definitions to your code.
A way to add IntelliSense support is using TypeScript’s interface merging. For example, the HttpRequest
class in the Supercharge framework is macroable. Any third-party package adding methods to the request can also inject typings using declaration merging. Merge your types by defining a module for the extended package and export the extended interface:
declare module '@supercharge/http' {
export interface HttpRequest {
session(): Session
}
}
You should add the extended interface declarations in your typings file (typically a .d.ts
file) or in one of your package’s exported files.