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

TypeScript递归实现嵌套对象至少一个属性必填的方案咨询

递归实现TypeScript嵌套对象至少一个属性必填

问题分析

需要限制包含嵌套子对象的TypeScript类型至少填写一个属性,单层的AtLeastOne类型可以满足平面对象需求,但递归版本无法生效;同时顶层可选属性(如GlobalOptions中的draggableOptions)若传入则必须满足至少一个属性的要求。

解决方案

核心类型实现

先定义辅助类型判断对象类型,再结合递归转换与单层AtLeastOne实现递归版本:

// 判断是否为需要递归处理的非基础对象(排除数组、函数、内置对象等)
type IsObject<T> = 
  T extends object 
    ? T extends Array<any> | Function | Date | RegExp ? false : true 
    : false;

// 单层对象至少一个属性必填的实现
type AtLeastOne<T> = {
  [K in keyof T]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<keyof T, K>>>;
}[keyof T];

// 递归转换对象的每个属性:将嵌套对象类型替换为递归的AtLeastOne
type RecursiveObjectTransform<T> = {
  [K in keyof T]: 
    IsObject<T[K]> extends true 
      ? RecursiveAtLeastOne<T[K]> 
      : T[K];
};

// 递归版至少一个属性:顶层必须至少有一个属性,嵌套对象若传入也必须满足至少一个属性
type RecursiveAtLeastOne<T> = AtLeastOne<RecursiveObjectTransform<T>>;

应用到你的类型定义

1. 处理DraggableOptions与DroppableOptions

直接用RecursiveAtLeastOne包裹原类型即可:

type DraggableOptions = {
  identifier?: {
    id?: string;
    type?: string;
  };
  modifiers?: {
    dropEffect?: "copy" | "move";
  };
  data?: any;
}

export type DroppableOptions = {
  identifier: {
    id?: string;
    type?: string[];
  };
  modifiers?: {
    highlight?: {
      on: "dragmove" | "dragover";
      class: string;
    };
  };
};

// 转换为递归至少一个属性的类型
type ValidDraggable = RecursiveAtLeastOne<DraggableOptions>;
type ValidDroppable = RecursiveAtLeastOne<DroppableOptions>;

此时:

  • 有效示例:{ data: "test" }、{ identifier: { id: "1" } }、{ modifiers: { dropEffect: "move" } }
  • 无效示例:{}、{ identifier: {} }、{ modifiers: {} }

2. 处理GlobalOptions

顶层可选属性若传入则必须满足递归至少一个属性的要求,直接替换类型即可:

export type GlobalOptions = {
  draggableOptions?: ValidDraggable;
  droppableOptions?: ValidDroppable;
};

为什么之前的递归版本无效

你之前的递归实现仅对每个嵌套属性应用了AtLeastOne,但未保证顶层对象至少有一个属性被填写,同时也没有处理“可选属性仅在传入时需要满足必填规则”的逻辑,导致空对象仍能通过类型校验。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 08:41:04