You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何访问未实例化类(DTO)中仅定义类型未赋值的属性?

验证请求体属性是否属于DTO的解决方案

核心问题:TypeScript类的属性仅为类型标注,编译为JavaScript后不会自动存在于类原型或实例中,因此直接通过CreateUserDTO.prototype.birthAt这类方式无法获取属性列表。

方法一:使用NestJS官方ValidationPipe(推荐)

NestJS的ValidationPipe自带白名单功能,可直接实现“请求体属性必须属于DTO”的验证,无需自定义逻辑:

在main.ts中全局配置管道:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe({
    whitelist: true, // 自动移除DTO中未定义的属性
    forbidNonWhitelisted: true, // 若存在DTO外的属性,直接抛出400错误
    transform: true, // 自动将请求体转换为DTO实例(可选,增强类型安全)
  }));
  await app.listen(3000);
}
bootstrap();

开启forbidNonWhitelisted后,只要请求体包含DTO未定义的属性,就会直接返回错误,完全满足需求。

方法二:自定义逻辑(通过反射/Class-Transformer获取DTO属性)

若需自定义验证逻辑,可借助class-transformer的元数据存储来获取DTO的所有属性:

1. 获取DTO属性列表

import { getMetadataStorage } from 'class-transformer';

function getDTOPropertyNames(dtoClass: any): string[] {
  const metadataStorage = getMetadataStorage();
  const targetMetadata = metadataStorage.getTargetMetadata(dtoClass);
  return targetMetadata ? targetMetadata.map(item => item.propertyName) : [];
}

// 示例调用
const userDTOProps = getDTOPropertyNames(CreateUserDTO);
console.log(userDTOProps); // 输出 ['name', 'email', 'password', 'birthAt']

2. 在自定义Interceptor中验证

假设你已通过自定义装饰器将DTO类存入执行上下文的元数据中,可在Interceptor中对比属性:

import { Injectable, NestInterceptor, ExecutionContext, CallHandler, BadRequestException } from '@nestjs/common';
import { Observable } from 'rxjs';
import { getMetadataStorage } from 'class-transformer';

@Injectable()
export class DTOPropertyValidationInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request = context.switchToHttp().getRequest();
    const requestBody = request.body;
    // 从元数据中获取目标DTO类(需提前通过自定义装饰器设置)
    const targetDTO = Reflect.getMetadata('target-dto', context.getHandler());

    // 获取DTO的所有属性名
    const metadataStorage = getMetadataStorage();
    const dtoProps = metadataStorage.getTargetMetadata(targetDTO)?.map(item => item.propertyName) || [];
    const bodyProps = Object.keys(requestBody);

    // 找出请求体中不属于DTO的属性
    const invalidProps = bodyProps.filter(prop => !dtoProps.includes(prop));
    if (invalidProps.length > 0) {
      throw new BadRequestException(`请求体包含无效属性:${invalidProps.join(', ')}`);
    }

    return next.handle();
  }
}

补充说明

TypeScript类的属性仅在编译时做类型检查,编译为JS后不会自动挂载到类或原型上,因此直接访问CreateUserDTO.prototype.birthAt会返回undefined。必须通过元数据(如class-validator/class-transformer存储的装饰器元数据)来获取属性信息。

内容的提问来源于stack exchange,提问作者Yuri Silva

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 03:25:19