Use exported modules as a union type

Issue

I am trying to figure out a way to use exported modules’ list as a type. Let’s say I have three files:

// schemas/auth.ts
import Joi, { Schema } from 'joi';

export const login: Schema = Joi.object({
  username: Joi.string().alphanum().min(3).max(30).required(),
  password: Joi.string().pattern(new RegExp('^[a-zA-Z0-9]{3,30}$')),
});
// schemas/index.ts
import { login } from './auth';

export default { login };

And, for the validation middleware:

import { NextFunction, Request, Response } from 'express';

import schemas from '../schemas';

export default (schema: string) => {
  if (!schemas.hasOwnProperty(schema))
    throw new Error(`'${schema}' validator is not exist`);

  return async function (req: Request, _res: Response, next: NextFunction) {
    try {
      const validated = await schemas[schema].validateAsync(req.body);
      req.body = validated;
      next();
    } catch (err) {
      if (err.isJoi) console.log(err);

      // return next(createHttpError(422, { message: err.message }));
      next();
    }
  };
};

This validator will not work as is because TypeScript cannot be sure if passed in schema string has a corresponding module in schemas, so I have to somehow say "Parameter schema can only be one of the exported modules’ name". What would be the best way to achieve this?

Solution

You can use type keyof typeof schemas to have validation function only accept strings that exist as key of schemas.

TS Documentation: https://www.typescriptlang.org/docs/handbook/2/keyof-types.html

Answered By – Joonas

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published