unbound-method
Enforce unbound methods are called with their expected scope.
Extending"plugin:@typescript-eslint/recommended-type-checked" in anESLint configuration enables this rule.
This rule requirestype information to run, which comes with performance tradeoffs.
Class method functions don't preserve the class scope when passed as standalone variables ("unbound").If your function does not accessthis,you can annotate it withthis: void, or consider using an arrow function instead.Otherwise, passing class methods around as values can remove type safety by failing to capturethis.
This rule reports when a class method is referenced in an unbound manner.
If you're working withjest, you can useeslint-plugin-jest's version of this rule to lint your test files, which knows when it's ok to pass an unbound method toexpect calls.
- Flat Config
- Legacy Config
exportdefault tseslint.config({
rules:{
"@typescript-eslint/unbound-method":"error"
}
});
module.exports={
"rules":{
"@typescript-eslint/unbound-method":"error"
}
};
Try this rule in the playground ↗
Examples
- ❌ Incorrect
- ✅ Correct
classMyClass{
publiclog():void{
console.log(this);
}
}
const instance=newMyClass();
// This logs the global scope (`window`/`global`), not the class instance
const myLog= instance.log;
myLog();
// This log might later be called with an incorrect scope
const{ log}= instance;
// arith.double may refer to `this` internally
const arith={
double(x:number):number{
return x*2;
},
};
const{ double}= arith;
Open in PlaygroundclassMyClass{
publiclogUnbound():void{
console.log(this);
}
publiclogBound=()=>console.log(this);
}
const instance=newMyClass();
// logBound will always be bound with the correct scope
const{ logBound}= instance;
logBound();
// .bind and lambdas will also add a correct scope
const dotBindLog= instance.logUnbound.bind(instance);
constinnerLog=()=> instance.logUnbound();
// arith.double explicitly declares that it does not refer to `this` internally
const arith={
double(this:void, x:number):number{
return x*2;
},
};
const{ double}= arith;
Open in PlaygroundOptions
This rule accepts the following options:
typeOptions=[
{
/** Whether to skip checking whether `static` methods are correctly bound. */
ignoreStatic?:boolean;
},
];
const defaultOptions: Options=[{ ignoreStatic:false}];
ignoreStatic
Whether to skip checking whetherstatic methods are correctly bound. Default:false.
Examples ofcorrect code for this rule with{ ignoreStatic: true }:
classOtherClass{
staticlog(){
console.log(OtherClass);
}
}
// With `ignoreStatic`, statics are assumed to not rely on a particular scope
const{ log}= OtherClass;
log();
Open in PlaygroundWhen Not To Use It
If your project dynamically changesthis scopes around in a way TypeScript has difficulties modeling, this rule may not be viable to use.For example, some functions have an additional parameter for specifying thethis context, such asReflect.apply, and array methods likeArray.prototype.map.This semantic is not easily expressed by TypeScript.You might consider usingESLint disable comments for those specific situations instead of completely disabling this rule.
If you're wanting to usetoBeCalled and similar matches injest tests, you can disable this rule for your test files in favor ofeslint-plugin-jest's version of this rule.
Type checked lint rules are more powerful than traditional lint rules, but also require configuringtype checked linting.
SeeTroubleshooting > Linting with Type Information > Performance if you experience performance degradations after enabling type checked rules.