#How to Handle TypeScript's Null Checks for an Object Guaranteed by Middleware?

10 messages · Page 1 of 1 (latest)

halcyon moon
#

In my Express.js application, I have a series of middleware functions. By the design of these functions, if the request reaches a particular point (say, a controller function), it's guaranteed that certain request properties (like req.user) have been set by earlier middleware. However, TypeScript's strict null checks still require me to handle cases where these properties might be null or undefined. I want to avoid using TypeScript's non-null assertion operator (!) excessively, as it feels like bypassing the system rather than using it properly. Additionally, I'd prefer not to insert manual checks for these properties again in my controllers or other middleware since these checks have already been conclusively handled in previous middleware.

Is there a best practice for asserting the presence of object properties in TypeScript when their existence is ensured by the application's logic (such as prior middleware ensuring req.user is defined)? What's a clean, safe way to handle this scenario without littering my code with unnecessary checks or assertions?

Example:

router.get(
  '/',
  authRequired(), // made sure here that req.user will exists
  abc(),
  xyz(),
  usersControllers.getAllUsers
)

getAllUsers Controller

const getAllUsers = async (req: AuthRequest, res: Response): Promise<Response> => {
  const { userId, role } = req.user

AuthRequest:

export interface AuthRequest extends Request {
  user?: {
    userId: number
    role: string
  }
}
sturdy heart
#

There isn't really a good way to do this within the express paradigm. This is a general problem with having "state" that can be set/accessed anywhere

#

The solution is a functional programming style, when step A calls step B with only the correct information

#

You could ditch the idea of middleware and handler, and just have a single handler, that calls the handlers directly.

halcyon moon
#

considering i don't have that luxury of ditching the idea of middleware, so next best idea would be check manually everywhere?

Example:

const getAllUsers = async (req: AuthRequest, res: Response): Promise<Response> => {
  const { user } = req

  if (user === undefined) {
    throw new Error('User details not available')
  }

  const { userId, role } = user

  try {
    // ...
sturdy heart
#

checks or assertions (!), your choice

sturdy heart
halcyon moon
#

got it.

halcyon moon
# sturdy heart Why can't you ditch middleware?

i am working with other devs, so might not this luxury.
but my reasons of not ditching could be:

  1. i find them more readable like just by seeing routes i can tell this need authentication, who can access it, stuff like this..
  2. another reason could be community standards may be
sturdy heart
#

You can do it that way if you like. But I think express is a very old lib, made before TS. So it might not be the best way to do it now.