Когда я получаю обратный вызов 'catch', 'this' не определено, даже используя функции стрелок. Любые идеи?

private all(req: Request, res: Response): void {
    EntityRepository.getRepositoty(req.params.etName).then(repo => {

        ...

    }).catch((err) => {
        this.handleError(res, err); // here I get undefined.
    });
}

как называется весь функционал.

Он называется на основе экспресс-маршрута.

Добавил mathod bind, как предложил @ jfriend00.

constructor() {
    // Connect to database.
    DataAccess.connect();

    // Starts configuring routes for api
    this.router = Router();

    // Bad request due to absence of entity type.
    this.router.get("/", (req, res) => {
        res.statusCode = 400;
        res.statusMessage = SysMsgs.error.noEntityTypeSpecified.message;
        res.send();
    });

    // Added method 'bind'.
    this.router.get(this.routeBase, this.all.bind(this));
    this.router.get(this.routeBase + "/:id", this.findOne.bind(this));
}
3
Leandro 28 Май 2017 в 03:01

2 ответа

Лучший ответ

С помощью функций стрелок this сохранит значение, которое имело в области действия до вызова функции стрелки. В вашем случае это означает, что оно будет иметь любое значение this, которое было в начале вашей функции all. Таким образом, это значение this зависит от того, как вызывается функция all.

И, исходя из вашего this.router.get(), где вы указываете this.all в качестве обратного вызова, это означает, что this внутри all будет установлено на то, что Express установит для него при вызове этого Перезвони. И это undefined.

Вы можете исправить проблему, используя .bind().

 this.router.get(this.routeBase, this.all.bind(this));

Это гарантирует, что соответствующий this установлен при запуске .all(). И тогда ваша arrow функция внутри all() будет использовать это значение this.

Примечание: вам нужно будет использовать .bind() для любого метода, который вы передаете в качестве обратного вызова, где вы ожидаете, что this будет объектом внутри обратного вызова. Когда вы передаете что-то вроде this.all, значение this теряется и передается только ссылка на метод. Затем вызывающая сторона вызывает этот метод как обычную функцию без привязки объекта. Вы используете .bind(), чтобы взять это под контроль самостоятельно. .bind() по существу создает небольшую функцию-заглушку, которая повторно присоединяет соответствующий указатель this, вызывая ваш метод, используя его.


Вы также можете сделать свою собственную функцию стрелки обертки для него:

 this.router.get(this.routeBase, (req, res) => this.all(req, res));

Который, как указывает Саравана, сохранит проверку типа TypeScript.

4
jfriend00 28 Май 2017 в 06:06

Хотя ответ @ jfriend00 охватывает проблему с вашим кодом, и в использовании bind в JavaScript нет ничего плохого, однако при использовании bind в TypeScript есть небольшая проблема. Подпись типа для bind:

bind(this: Function, thisArg: any, ...argArray: any[]): any;

Обратите внимание, что bind возвращает any, что означает, что любые проверки типов возвращаемой функции отключены, что приводит к незначительным ошибкам. Возьмем, к примеру, следующее:

// Assume the definition for `router.get` is something similar to this:
get(routeBase: string, callback: (req: Request, resp: Response) => void)

// ... and in the place you are calling it
private all(param: number): void {
}

this.route.get(this.routeBase, this.all.bind(this)); 
// No compiler error, but `all` and the callback parameter expected by `route.get` don't match!

Если вы хотите продолжить проверку типов, вы можете использовать что-то вроде ниже вместо bind:

this.route.get((req, resp) => this.all(req, resp));

См. https://github.com/Microsoft/TypeScript/issues/212.

2
Saravana 28 Май 2017 в 03:08