I have a class Chain
with a method syncPassRequest
in which I used the apply()
method to set a class instance as another function's (this.fn) this
. When I tried console.log(this)
in a function which will be passed to the class instance, I found there is an error
"An outer value of 'this' is shadowed by this container."
I was expecting to get this as the class instance, because I used apply to pass it.
Why I want to do this? It's because I want to get another method asyncPassRequest
from the class instance to meet the async need.
(This was in a practice of chain of responsibility)
This is the class declaration
type ChainFunc = (...args: any) => any;
export class Chain {
public fn: ChainFunc;
public successor: Chain | null = null;
constructor(fn: ChainFunc) {
this.fn = fn;
}
public setSuccessor(successor: Chain | null): any {
return (this.successor = successor);
}
public syncPassRequest(...args: any): any {
// here, i use apply to bind class Chain's instance to fn's this
const res = this.fn.apply(this, args);
console.log(this.fn.name, res);
if (res === "nextSuccessor") {
return (
this.successor &&
this.successor.syncPassRequest.apply(this.successor, args)
);
}
return res;
}
public asyncPassRequest(...args: any) {
this.successor &&
this.successor.syncPassRequest.apply(this.successor, args);
}
}
this is the function declaration
import { Chain } from "./chain_of_responsibility";
function fn1(msg: string) {
if (msg === "pass") {
console.log("fn1 pass");
return "nextSuccessor";
}
console.log("fn1 stop");
return "stop";
}
function fn2(msg: string) {
setTimeout(() => {
// here, i wanted to console.log this, i was expecting the class Chain's instance
// but it gave me an error
console.log(this);
// i want to use this.asyncPassRequest to meet the async need
this.asyncPassRequest();
}, 1000);
}
function fn3(msg: string) {
if (msg === "pass") {
console.log("fn3 pass");
return "nextSuccessor";
}
console.log("fn3 stop");
return "stop";
}
const c1 = new Chain(fn1);
const c2 = new Chain(fn2);
const c3 = new Chain(fn3);
c1.setSuccessor(c2);
c2.setSuccessor(c3);
c1.syncPassRequest("pass");
I tried to use arrow function to declare the function, but I failed, because arrow function is cannot have their this
value changed with apply()
, bind()
, or call()
.
This is the error I got
dh@localhost chain_of_responsbility % ts-node test.ts
/Users/dh/.nvm/versions/node/v12.15.0/lib/node_modules/ts-node/src/index.ts:859
return new TSError(diagnosticText, diagnosticCodes, diagnostics);
^
TSError: ⨯ Unable to compile TypeScript:
test.ts:14:17 - error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.
14 console.log(this);
~~~~
test.ts:12:10
12 function fn2(msg: string) {
~~~
An outer value of 'this' is shadowed by this container.
test.ts:15:5 - error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.
15 this.asyncPassRequest();
~~~~
test.ts:12:10
12 function fn2(msg: string) {
~~~
An outer value of 'this' is shadowed by this container.
at createTSError (/Users/dh/.nvm/versions/node/v12.15.0/lib/node_modules/ts-node/src/index.ts:859:12)
at reportTSError (/Users/dh/.nvm/versions/node/v12.15.0/lib/node_modules/ts-node/src/index.ts:863:19)
at getOutput (/Users/dh/.nvm/versions/node/v12.15.0/lib/node_modules/ts-node/src/index.ts:1077:36)
at Object.compile (/Users/dh/.nvm/versions/node/v12.15.0/lib/node_modules/ts-node/src/index.ts:1433:41)
at Module.m._compile (/Users/dh/.nvm/versions/node/v12.15.0/lib/node_modules/ts-node/src/index.ts:1617:30)
at Module._extensions..js (node:internal/modules/cjs/loader:1272:10)
at Object.require.extensions.<computed> [as .ts] (/Users/dh/.nvm/versions/node/v12.15.0/lib/node_modules/ts-node/src/index.ts:1621:12)
at Module.load (node:internal/modules/cjs/loader:1081:32)
at Function.Module._load (node:internal/modules/cjs/loader:922:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12) {
diagnosticCodes: [ 2683, 2683 ]
}