3

Specifically, I'm trying to setup server sided typescript compilation for express.

One of the interfaces exposed is RequestHandler, with the following structure:

// express-serve-static-core/index.d.ts

declare module "express-serve-static-core" {
  ...

  interface RequestHandler {
    (req: Request, res: Response, next: NextFunction): any;
  }
}

I wrote the following class:

import * as express from "express";

class PageNotFound implements express.RequestHandler {

  constructor (req: express.Request, res: express.Response, next: express.NextFunction) {
    let viewFilePath: string = "404";
    let statusCode: number = 404;
    let result: Object = {
      status: statusCode,
    };

    res.status(statusCode);
    res.render(viewFilePath, {}, function (err: Error, html: string): void {
      if (err) {
        res.status(statusCode).json(result);
      }
      res.send(html);
    });
  }
}

However, this throws the error:

error TS2345: Argument of type 'typeof PageNotFound' is not assignable to parameter of type 'RequestHandler'. Type 'typeof PageNotFound' provides no match for the signature '(req: Request, res: Response, next: NextFunction): any'

Any suggestions out there? I'm not sure what I'm doing wrong.

Alexander
  • 841
  • 1
  • 9
  • 23

2 Answers2

3

RequestHandler is an interface that is specifying something with a call signature, which classes cannot implement. You want a regular function:

function pageNotFound(req: express.Request, res: express.Response, next: express.NextFunction) {
    ...
}

If the interface had new in front of the method signature, it would be defining the shape of the constructor of your class, but that isn't the case.

Another way to think about it is this: when you use a class, you're defining a function that must be called with new. Is Express going to call "new PageNotFound(...)" or is it calling "pageNotFound(...)"?

As Ryan Cavanaugh, one of the TypeScript developers, put it here:

More formally, a class implementing an interface is a contract on what an instance of the class has... – Ryan Cavanaugh Nov 15 '12 at 23:57

Community
  • 1
  • 1
Alan
  • 408
  • 3
  • 12
  • That is correct. I also added the type definition `: void` and `"use strict";` due to tslint complaining. Thanks, Alan! – Alexander Apr 22 '16 at 16:51
0

You want to keep it simple, classes are for objects that are used more than once. The module express provides for you the Router object with the correct properties.

import * as express from 'express';
const router = express.Router();

router.get('/', (req: express.Request, res: express.Response, next: express.NextFunction) => {
    res.render('index', {
        title: 'Express'
    })
});

export = router; 
Rick
  • 12,606
  • 2
  • 43
  • 41