繁体   English   中英

TS 摘要 class - 无法读取未定义的属性“路由”

[英]TS abstract class - cannot read property 'routes' of undefined

我正在用 express.js 和 typescript 构建一个服务器,我有抽象 class Controller是所有控制器的基础 class,我有AuthController处理身份验证逻辑的 AuthController。 当我向服务器发出 post 请求时,出现错误,如下所示:

TypeError: Cannot read property 'routes' of undefined
    at setRoutes (C:\path\to\project\dist\typings\Controller.js:12:34)
    at Layer.handle [as handle_request] (C:\path\to\project\node_modules\express\lib\router\layer.js:95:5)
    at trim_prefix (C:\path\to\project\node_modules\express\lib\router\index.js:317:13)
    at C:\path\to\project\node_modules\express\lib\router\index.js:284:7
    at Function.process_params (C:\path\to\project\node_modules\express\lib\router\index.js:335:12)
    at next (C:\path\to\project\node_modules\express\lib\router\index.js:275:10)
    at expressInit (C:\path\to\project\node_modules\express\lib\middleware\init.js:40:5)
    at Layer.handle [as handle_request] 
    ...

配置文件:

{
    "compilerOptions": {
    "target": "es6",                   
    "module": "commonjs",                    
    "outDir": "./dist",                        
    "noEmitOnError": true,
    "strict": true,                           
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true
  }
}

摘要 controller class:

export default abstract class Controller {
    public router: Router = Router();
    public abstract path: string;
    protected abstract routes: Array<IRoute> = [];

    public setRoutes(): Router {
        for (const route of this.routes) {
            for (const mw of route.localMiddleware) {
                this.router.use(route.path, mw)
            };
            switch (route.method) {
                case 'GET':
                    this.router.get(route.path, route.controller);
                    break;
                case 'POST':
                    this.router.post(route.path, route.controller);
                    console.log('set to post')
                    break;
                case 'PUT':
                    this.router.put(route.path, route.controller);
                    break;
                case 'DELETE':
                    this.router.delete(route.path, route.controller);
                    break;
                default:
                    console.log('not a valid method')
                    break;
            };
        };

        return this.router;
    }
};

路由接口:

export interface IRoute {
    path: string;
    method: 'GET' | 'POST' | 'PUT' | 'DELETE';
    controller: (req: Request, res: Response, next: NextFunction) => Promise<void>;
    localMiddleware: ((req: Request, res: Response, next: NextFunction) => void)[]
};

授权 controller class:

export default class AuthController extends Controller {
    public path = '/';
    readonly routes: IRoute[] = [
        {
            path: '/login',
            method: 'POST',
            controller: this.handleLogin,
            localMiddleware: []
        },
        {
            path: '/register',
            method: 'POST',
            controller: this.handleRegister,
            localMiddleware: []
        }
    ];

    constructor() {
        super();
    };

    async handleLogin(req: Request, res: Response, next: NextFunction): Promise<void> {
        // some logic
    };

    async handleRegister(req: Request, res: Response, next: NextFunction): Promise<void> {
        // some logic
    };
}

我这样做是为了使用服务器 class 中的路由:

public loadControllers(controllers: Array<Controller>): void {
    controllers.forEach(controller => {
        this.app.use(controller.path, controller.setRoutes);
    });
};

然后像这样在 app.ts 中初始化它们:

const controllers: Array<Controller> = [
    new AuthController(),
    new MatchmakingController(),
];
server.loadControllers(controllers);

loadControllers function 中,您将setRoutes方法绑定为快速处理程序的回调。 你不知道什么时候以及谁会调用回调 function,在通常情况下(谁调用 express 处理函数)是undefined ,这就是this.routes throws TypeError: Cannot read property 'routes' of undefined错误的原因。

我认为我们有两种方法可以解决这个问题:

  1. setRoutes方法绑定this context (我推荐): loadControllers function。
this.app.use(controller.path, controller.setRoutes.bind(controller)); // binding controller as `this`
  1. 使用箭头 function 来“修复”这个关键字 scope:摘要 controller class
public setRoutes = (): Router => { // Now, setRoutes is a property
    // method content
    // Now, "this" alway is this controller
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM