You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript调用getNotesHandler时_service为undefined的问题求助

问题描述

调用getNotesHandler()时出现如下错误:

TypeError: Cannot read properties of undefined (reading '_service')
  at ...
  at ...
  at ...

完整代码如下:

import { Request, ResponseObject, ResponseToolkit } from "@hapi/hapi";
import { ClientError } from "../../exceptions/ClientError";
import { NotesService } from "../../services/inMemory/NotesService";
import { notesValidator, NotesValidator } from "../../validator/notes";

export class NotesHandler {
  _service: NotesService = new NotesService();
  _validator: NotesValidator;
  
  constructor(service: NotesService, validator: NotesValidator) {
    this._service = service;
    this._validator = validator;
    console.log('Service initialized', this._service)
    console.log('Validator initialized', this._validator)
  }

  postNoteHandler(request: Request, h: ResponseToolkit): ResponseObject {
    try {
      this._validator.validateNotePayload(request.payload);
      const data: NoteInput = JSON.parse(request.payload.toString());

      const noteId = this._service.addNote(data.title, data.body, data.tags);

      const response = h.response({
        status: 'success',
        message: `Note with id ${noteId} was added`,
        data: {
          noteId,
        }
      });

      response.code(201);
      return response;
    } catch(error) {
      if (error instanceof ClientError) {
        const response = h.response({
          status: 'error',
          message: error.message,
        });

        response.code(error.statusCode);
        return response;
      }

      // Server Error
      const response = h.response({
        status: 'error',
        message: 'Internal server error',
      });
      response.code(500);
      console.error(error);
      return response;
    }
  }

  getNotesHandler(request: Request, h: ResponseToolkit): ResponseObject {
    console.log("getNotesHandler");
    const notes = this._service.getNotes();
    const response = h.response({
      status: 'success',
      message: 'Notes were retrieved',
      data: notes,
    });
    response.code(200);
    return response;
  }

  getNoteByIdHandler(request: Request, h: ResponseToolkit): ResponseObject {
    try {
      const noteId = request.params.id;
      const note = this._service.getNoteById(noteId);
      const response = h.response({
        status: 'success',
        data: {
          note,
        }
      });
      response.code(200);
      return response;
    } catch(error) {
      if (error instanceof ClientError) {
        const response = h.response({
          status: 'error',
          message: error.message,
        });

        response.code(error.statusCode);
        return response;
      }

      // Server Error
      const response = h.response({
        status: 'error',
        message: 'Internal server error',
      });
      response.code(500);
      console.error(error);
      return response;
    }
  }

  putNoteByHandler(request: Request, h: ResponseToolkit): ResponseObject {
    try {
      this._validator.validateNotePayload(request.payload);
      const noteId = request.params.id;

      this._service.editNoteById(
        noteId, JSON.parse(request.payload.toString())
      );

      const response = h.response({
        status: 'success',
        message: `Note with id ${noteId} was edited`,
      });
      return response;
    } catch(error) {
      if (error instanceof ClientError) {
        const response = h.response({
          status: 'fail',
          message: error.message,
        });
        response.code(error.statusCode);
        return response;
      }
 
      // Server ERROR!
      const response = h.response({
        status: 'error',
        message: 'Server goes error.',
      });
      response.code(500);
      console.error(error);
      return response;
    }
  }

  deleteNoteByIdHandler(request: Request, h: ResponseToolkit): ResponseObject {
    try {
      const noteId = request.params.id;
      this._service.deleteNoteById(noteId);
      const response = h.response({
        status: 'success',
        message: `Note with id ${noteId} was deleted`,
      });
      return response;
    } catch(error) {
      if (error instanceof ClientError) {
        const response = h.response({
          status: 'fail',
          message: error.message,
        });
        response.code(error.statusCode);
        return response;
      }
 
      // Server ERROR!
      const response = h.response({
        status: 'error',
        message: 'Server goes error.',
      });
      response.code(500);
      console.error(error);
      return response;
    }
  }
}

构造函数中通过console.log(this._service)验证,控制台输出显示_service已正常初始化:

Service initialized NotesService { _notes: [] }
Validator initialized { validateNotePayload: [Function: validateNotePayload] }

但调用getNotesHandler()时,_service和_validator均为undefined,其他类方法存在同样问题。

解决方案

这个问题的核心是类方法的this绑定丢失。当在Hapi中注册路由时,如果直接将handler设置为类的方法(比如handler: notesHandler.getNotesHandler),方法会脱离类实例的上下文执行,导致this指向undefined(严格模式下),自然无法访问_service和_validator。

以下是三种可行的解决方式:

1. 在构造函数中手动绑定this

修改NotesHandler的构造函数,将所有需要用到的方法的this绑定到当前实例:

constructor(service: NotesService, validator: NotesValidator) {
  this._service = service;
  this._validator = validator;
  // 绑定this到类实例
  this.postNoteHandler = this.postNoteHandler.bind(this);
  this.getNotesHandler = this.getNotesHandler.bind(this);
  this.getNoteByIdHandler = this.getNoteByIdHandler.bind(this);
  this.putNoteByHandler = this.putNoteByHandler.bind(this);
  this.deleteNoteByIdHandler = this.deleteNoteByIdHandler.bind(this);
  
  console.log('Service initialized', this._service)
  console.log('Validator initialized', this._validator)
}

2. 使用箭头函数定义类方法

箭头函数会自动捕获当前上下文的this,可以直接替换类中的方法定义:

postNoteHandler = (request: Request, h: ResponseToolkit): ResponseObject => {
  // 原方法内容不变
}

getNotesHandler = (request: Request, h: ResponseToolkit): ResponseObject => {
  // 原方法内容不变
}

// 其他方法同理替换为箭头函数

3. 在注册路由时绑定this

如果不想修改类的内部实现,可以在注册Hapi路由时,通过bind指定this为类实例:

const notesHandler = new NotesService(...);

server.route({
  method: 'GET',
  path: '/notes',
  handler: notesHandler.getNotesHandler.bind(notesHandler)
});

选择任意一种方式都能解决this指向错误的问题,推荐第一种或第二种,代码更简洁且易于维护。

内容的提问来源于stack exchange,提问作者Muhammad Alif Darmamulia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 15:09:12