Reputation: 1856
I have following Nestjs DTO class:
// create-job-offer.dto.ts
import { IsOptional, IsNumber } from 'class-validator';
export class CreateJobOfferDto {
@IsNumber()
@IsOptional()
mentorId: number;
@IsNumber()
@IsOptional()
companyId: number;
}
I want to obtain the list of class properties: ['mentorId', 'companyId']
.
I tried so far in a controller without success following methods:
Object.getOwnPropertyNames(new CreateJobOfferDto());
Object.getOwnPropertyNames(CreateJobOfferDto);
Object.getOwnPropertySymbols(new CreateJobOfferDto());
Object.getOwnPropertySymbols(CreateJobOfferDto);
Object.getOwnPropertyDescriptors(CreateJobOfferDto);
Object.getOwnPropertyDescriptors(new CreateJobOfferDto());
Object.getPrototypeOf(CreateJobOfferDto);
Object.getPrototypeOf(new CreateJobOfferDto());
If I add a method, or vars in a constructor, I can get them, but not the properties.
The reason why I want to achieve this is, I am using Prisma and React, and in my React app I want to receive the list of class properties so that I can generate a model form dynamically.
Upvotes: 2
Views: 3206
Reputation: 31
As well as the custom solution Mostafa proposes, you can use the @Expose
decorator combined with the plainToInstance
function from the class-transformer
library.
import { Expose } from 'class-transformer';
export class UserDto {
@Expose()
@IsNotEmpty()
firstName: string;
@Expose()
@IsEmail()
@IsOptional()
public readonly email: string;
}
And to get the keys:
import { plainToInstance } from 'class-transformer';
import { UserDto } from './userDto';
const userDtoInstance = plainToInstance(UserDto, {});
console.log(Object.keys(userDtoInstance));
Upvotes: 0
Reputation: 3667
There is no easy direct way to get the list of properties of a DTO class, or more comprehensively, any type of class that has only properties.
The reason is that whenever you defined a property without any values, it becomes disappears after compiling to javascript.
Example:
// typescript
class A {
private readonly property1: string;
public readonly property2: boolean;
}
it compiles to this:
// javascript
"use strict";
class A {}
In order to achieve this goal, you need to write a custom decorator. like this:
const properties = Symbol('properties');
// This decorator will be called for each property, and it stores the property name in an object.
export const Property = () => {
return (obj: any, propertyName: string) => {
(obj[properties] || (obj[properties] = [])).push(propertyName);
};
};
// This is a function to retrieve the list of properties for a class
export function getProperties(obj: any): [] {
return obj.prototype[properties];
}
Imagine I have a DTO class for a user, like this:
import { getProperties } from './decorators/property.decorator';
export class UserDto {
@Property()
@IsNotEmpty()
firstName: string;
@Property()
@IsEmail()
@IsOptional()
public readonly email: string;
}
and I want to get all properties in a list, so we need to call the getProperties
method which we defined earlier, so:
import { UserDto } from './dtos/user.dto';
getProperties(UserDto); // [ 'firstName', 'email' ]
You can also use an npm module ts-transformer-keys.
A TypeScript custom transformer which enables to obtain keys of given type.
How to use:
import { keys } from 'ts-transformer-keys';
interface Props {
id: string;
name: string;
age: number;
}
const keysOfProps = keys<Props>();
console.log(keysOfProps); // ['id', 'name', 'age']
Upvotes: 5