Reputation: 3
I'm using nestjs with class validator to validate env variables, configuration.service.ts
is getting its values from configService file which get what it needs from .env and put it in a json object.
In the port and timeout properties I expect to receive a string since it came from a .env file, the decorator @Type(() => Number)
will try to convert whatever it receives into a Number. As far I'm concerned, the decorator only runs as the function call ends, so the function takes a string and returns a string and after that the string is casted into a Number.
The problem is the properties port and connectTimeoutMS expects a Number, the typescript lint claims it's receiving a string, looks like it's not recognizing the cast decorator. I want to know whether there's a way to get around this or I have to drop the cast decorator.
configuration.service.ts
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Type } from 'class-transformer';
import {
IsBoolean,
IsDefined,
IsInt,
IsNumber,
IsString,
} from 'class-validator';
import { ValidatedConfigService } from 'src/config/utils/validate.config';
import { DatabaseType, Logger } from 'typeorm';
@Injectable()
export class DatabaseConfigService extends ValidatedConfigService {
constructor(private configService: ConfigService) {
super();
}
@IsString()
@IsDefined()
get type(): DatabaseType {
return this.configService.get<DatabaseType>('database.type');
}
@IsString()
@IsDefined()
get host(): string {
return this.configService.get<string>('database.host');
}
@IsInt()
@IsDefined()
@Type(() => Number)
get port(): string {
return this.configService.get<string>('database.port');
}
@IsNumber()
@IsDefined()
@Type(() => Number)
get timeOut(): string {
return (
this.configService.get<string>('database.connectTimeoutMS') ||
'2000'
);
}
@IsString()
@IsDefined()
get entities(): string {
return this.configService.get<string>('database.entities');
}
}
database.configuration.ts
import { Injectable } from '@nestjs/common';
import { ConnectionOptions } from 'typeorm';
import { DatabaseConfigService } from './configuration.service';
export class DatabaseConfigController {
constructor(private readonly configService: DatabaseConfigService) {}
get settings(): ConnectionOptions {
return {
type: this.configService.type,
host: this.configService.host,
port: this.configService.port,
connectTimeoutMS: this.configService.timeOut,
entities: [this.configService.entities],
};
}
}
tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"target": "es2017",
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"incremental": true,
"skipLibCheck": true,
"strictNullChecks": false,
"noImplicitAny": false,
"strictBindCallApply": false,
"forceConsistentCasingInFileNames": false,
"noFallthroughCasesInSwitch": false
}
}
[Edit 12/20/21]
I had to give up from using the @Type()
decorator, as Micael Levi stated in his answer, this line is explicitly telling to TSC to expect a string get timeOut(): string
.
So I have to change it to number, but doing that I also need to change the type I am returning inside the function to either any or casting it to a number.
This way gives an obvious type error.
@IsInt()
@IsDefined()
get port(): number {
return this.configService.get<string>('db.port');
}
Not specifying the type will not trigger the lint but at runtime will throw an error due to the IsInt()
decorator because it's getting a string from database.configuration.ts
@IsInt()
@IsDefined()
get port(): number {
return this.configService.get('db.port');
}
The solution is casting it to a number by hand, this casting process also can be done in database.configuration.ts
.
@IsInt()
@IsDefined()
get port(): number {
return parseInt(this.configService.get<string>('db.port'), 10);
}
Maybe I was using the @Type()
decorator in a way that it is not intended to be used, tbh I never needed to use it, I just wanted to do all validations using this package.
Upvotes: 0
Views: 670
Reputation: 6665
In the following line you're (not TS) telling to TSC that this.configService.timeOut
is an string
get timeOut(): string
just change it to get timeOut(): number
. Decorators won't type anything for you.
Upvotes: 2