Automatically bind methods to their class instance
npx @tessl/cli install tessl/npm-auto-bind@5.0.0Auto Bind automatically binds methods to their class instance, eliminating the common issue of losing 'this' context when methods are detached from their objects. It traverses the prototype chain to find all methods and bind them to the instance, with support for filtering specific methods through include/exclude options using strings or regular expressions. The library includes a specialized React variant that automatically excludes React component lifecycle methods while binding custom methods.
npm install auto-bindimport autoBind from 'auto-bind';
import autoBindReact from 'auto-bind/react';For TypeScript with type definitions:
import autoBind, { Options } from 'auto-bind';
import autoBindReact from 'auto-bind/react';import autoBind from 'auto-bind';
class Unicorn {
constructor(name) {
this.name = name;
autoBind(this);
}
message() {
return `${this.name} is awesome!`;
}
}
const unicorn = new Unicorn('Rainbow');
// Grab the method off the class instance
const message = unicorn.message;
// Still bound to the class instance
message();
//=> 'Rainbow is awesome!'
// Without `autoBind(this)`, the above would have resulted in
//=> Error: Cannot read property 'name' of undefinedAutomatically bind methods in an object to their class instance. Works with inheritance and symbol properties.
/**
* Automatically bind methods to their class instance
* @param self - An object with methods to bind
* @param options - Optional configuration for filtering methods
* @returns The self object with bound methods
*/
function autoBind<SelfType extends Record<string, any>>(
self: SelfType,
options?: Options
): SelfType;Usage Examples:
import autoBind from 'auto-bind';
// Basic binding
class MyClass {
constructor() {
this.value = 'hello';
autoBind(this);
}
method() {
return this.value;
}
}
// With include filter (only bind specific methods)
class FilteredClass {
constructor() {
this.name = 'test';
autoBind(this, {include: ['bar']});
}
foo() {
return this.name; // Won't be bound
}
bar() {
return this.name; // Will be bound
}
}
// With exclude filter (bind all except specified methods)
class ExcludedClass {
constructor() {
this.name = 'test';
autoBind(this, {exclude: ['bar']});
}
foo() {
return this.name; // Will be bound
}
bar() {
return this.name; // Won't be bound
}
}
// With regular expressions
class RegexClass {
constructor() {
this.name = 'test';
autoBind(this, {include: [/^handle/]});
}
handleClick() {
return this.name; // Will be bound (matches /^handle/)
}
process() {
return this.name; // Won't be bound
}
}Same as autoBind but excludes default React component lifecycle methods, preventing interference with React's component lifecycle.
/**
* Same as autoBind but excludes default React component methods
* @param self - A React component instance with methods to bind
* @param options - Optional configuration for filtering methods
* @returns The self object with bound methods
*/
function autoBindReact<SelfType extends ReactComponent>(
self: SelfType,
options?: Options
): SelfType;Automatically Excluded Methods:
componentWillMount, UNSAFE_componentWillMountrendergetSnapshotBeforeUpdatecomponentDidMountcomponentWillReceiveProps, UNSAFE_componentWillReceivePropsshouldComponentUpdatecomponentWillUpdate, UNSAFE_componentWillUpdatecomponentDidUpdatecomponentWillUnmountcomponentDidCatchsetStateforceUpdateUsage Example:
import autoBindReact from 'auto-bind/react';
import React from 'react';
class Foo extends React.Component {
constructor(props) {
super(props);
autoBindReact(this);
}
// React lifecycle methods won't be bound
componentDidMount() {
// This won't be bound to maintain React functionality
}
// Custom methods will be bound
handleClick() {
// This will be properly bound
console.log('Clicked!');
}
render() {
return <button onClick={this.handleClick}>Click me</button>;
}
}interface Options {
/**
* Bind only the given methods
*/
readonly include?: ReadonlyArray<string | RegExp>;
/**
* Bind methods except for the given methods
*/
readonly exclude?: ReadonlyArray<string | RegExp>;
}
/**
* React Component base class type (from React library)
*/
type ReactComponent = {
setState(state: any): void;
forceUpdate(): void;
} & Record<string, any>;Auto Bind correctly handles inheritance by traversing the prototype chain:
class Base {
constructor(name) {
this.name = name;
}
message() {
return `${this.name} is awesome!`;
}
}
class Unicorn extends Base {
constructor(name) {
super(name);
autoBind(this); // Binds both inherited and own methods
}
greet() {
return `Hello, I'm ${this.name}`;
}
}
const unicorn = new Unicorn('Rainbow');
const { message, greet } = unicorn;
// Both inherited and own methods work when detached
message(); //=> 'Rainbow is awesome!'
greet(); //=> "Hello, I'm Rainbow"Auto Bind supports symbol-keyed methods:
const messageSymbol = Symbol('message');
class Unicorn {
constructor(name) {
this.name = name;
autoBind(this);
}
[messageSymbol]() {
return `${this.name} is awesome!`;
}
}
const unicorn = new Unicorn('Rainbow');
const message = unicorn[messageSymbol];
message(); //=> 'Rainbow is awesome!'