typescriptnestjsjoi

configService.get<T>('key') fails on type cast and joi on validation


I created a custom configuration file for my NestJs REST API. This is a simple example for the port the application is listening on.

I have a .env file with the content

SERVER_PORT = 3000

An example for my configuration file

import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import * as Joi from '@hapi/joi';

@Injectable()
export class ServerConfigService {
  constructor(private readonly configService: ConfigService) {
    const { error } = Joi.object({
      port: Joi.number()
        .port()
        .required(),
    }).validate({ port: this.port });

    if (error) { // no error thrown
      throw error;
    }

    console.log(typeof this.port); // type is string but should be number
  }

  public get port(): number {
    return this.configService.get<number>('SERVER_PORT');
  }
}

I would expect the ports type to be number but it's still a string. So two things come to my mind:

The port variable might be a bad example because Nest is able to deal with a port of type string. But other parts expect numbers and throw errors if a config variable should be a number but is of type string.

Did I miss something?


Solution

  • The example you found using the ConfigService is very misleading. What's misleading is the generic type parameter. The type you pass it only affects what the return value is treated as. The actual runtime type will be whatever the type is when it was read.

    NestJs uses dotenv to read the config files and all values are simply read as strings. No conversions are made.

    You should be using it like this:

    public get port(): number {
      return +this.configService.get('SERVER_PORT');
    }
    

    ConfigService source
    dotenv source