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

如何在TypeScript中将类的所有属性设为可选类型

在TypeScript中将类的所有属性设为可选(支持装饰器)

为什么直接继承Partial<CreateDTO>不行

Partial<T>是TypeScript的映射类型,仅作用于编译时的类型系统,它返回的是一个描述属性可选的类型,而非可被继承的类。类的继承只能针对具体的类(运行时存在的构造函数),因此无法直接继承Partial<CreateDTO>。

可行解决方案

因为需要给属性添加验证装饰器(运行时特性),必须显式定义类的属性,以下是几种常用方案:

方案1:手动标记属性为可选并实现Partial<CreateDTO>

直接在UpdateDTO中定义所有属性并添加?标记,同时实现Partial<CreateDTO>来保证类型与原类对齐,再给属性添加装饰器:

// 假设使用class-validator做验证
import { IsOptional, IsString, IsNumber } from 'class-validator';

class CreateDTO {
  @IsString()
  id: string;

  @IsString()
  name: string;

  @IsNumber()
  price: number;
}

class UpdateDTO implements Partial<CreateDTO> {
  @IsOptional()
  @IsString()
  id?: string;

  @IsOptional()
  @IsString()
  name?: string;

  @IsOptional()
  @IsNumber()
  price?: number;
}

方案2:封装装饰器减少重复代码

如果属性较多,可封装组合装饰器来避免重复写@IsOptional()和验证装饰器:

import { IsOptional, IsString, IsNumber, ValidationOptions } from 'class-validator';

// 封装可选字符串装饰器
function OptionalString(options?: ValidationOptions) {
  return function (target: any, propertyKey: string) {
    IsOptional()(target, propertyKey);
    IsString(options)(target, propertyKey);
  };
}

// 封装可选数字装饰器
function OptionalNumber(options?: ValidationOptions) {
  return function (target: any, propertyKey: string) {
    IsOptional()(target, propertyKey);
    IsNumber(options)(target, propertyKey);
  };
}

class CreateDTO {
  @IsString()
  id: string;

  @IsString()
  name: string;

  @IsNumber()
  price: number;
}

class UpdateDTO implements Partial<CreateDTO> {
  @OptionalString()
  id?: string;

  @OptionalString()
  name?: string;

  @OptionalNumber()
  price?: number;
}

方案3:继承原类并重写属性为可选(需处理父类构造函数)

如果需要继承原类的方法或其他逻辑,可重写属性为可选,但要注意父类构造函数的必填参数问题:

class CreateDTO {
  id: string;
  name: string;
  price: number;

  constructor(id: string, name: string, price: number) {
    this.id = id;
    this.name = name;
    this.price = price;
  }
}

class UpdateDTO extends CreateDTO {
  id?: string;
  name?: string;
  price?: number;

  constructor(id?: string, name?: string, price?: number) {
    // 父类构造函数需要必填参数,需传入默认值占位
    super(id ?? '', name ?? '', price ?? 0);
    // 覆盖父类属性值
    this.id = id;
    this.name = name;
    this.price = price;
  }
}

关键说明

  • 装饰器是运行时特性,必须显式定义类的属性才能添加装饰器,无法通过纯类型操作自动生成带装饰器的可选属性。
  • 使用implements Partial<CreateDTO>可以确保UpdateDTO的属性结构与原类一致,避免手动定义时出现遗漏或类型错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 00:05:30