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

如何实现泛型类型将Entity及其子对象的id和version设为可选?

问题描述

我们所有数据库表都包含标识符(id)和version属性,所有具体实体都继承自以下Entity接口:

interface Entity {
  id: number;
  version: number;
}

以下是一个多层级实体示例:

interface Address extends Entity {
    street: string;
    hno: string;
    zip: string;
    city: string;
    country: string;
}

interface Department extends Entity {
    name: string;
}

interface User extends Entity {
    name: string;
    birthday: string;
    address: Address;
    department: Department;
}

现在需要实现一个泛型类型,将所有层级(包括子对象)中的id和version字段改为可选类型。比如将User从:

type OriginalUser = {
    id: number;
    version: number;
    name: string;
    birthday: string;
    address: {
        id: number;
        version: number;
        street: string;
        hno: string;
        zip: string;
        city: string;
        country: string;
    };
    department: {
        id: number;
        version: number;
        name: string;
    };
}

转换为:

type TransformedUser = {
    id?: number;
    version?: number;
    name: string;
    birthday: string;
    address: {
        id?: number;
        version?: number;
        street: string;
        hno: string;
        zip: string;
        city: string;
        country: string;
    };
    department: {
        id?: number;
        version?: number;
        name: string;
    };
}

目前已有一个初步实现,但仅移除了id和version字段,缺少将其重新定义为可选类型的部分:

export type NewEntity<T extends Entity> = {
  // remove id and version fields
  [K in keyof Omit<T, 'id' | 'version'>]: T[K] extends Entity ? NewEntity<T[K]> : T[K];
};

需要完善该泛型类型以满足需求。

解决方案

通过交叉类型将移除的id/version字段重新定义为可选,同时递归处理所有嵌套的Entity类型:

export type PartialEntityIds<T extends Entity> = 
  // 将id和version设为可选
  Partial<Pick<T, 'id' | 'version'>> & 
  // 处理其他字段,递归嵌套的Entity
  {
    [K in keyof Omit<T, 'id' | 'version'>]: 
      T[K] extends Entity ? PartialEntityIds<T[K]> : T[K]
  };

代码说明

  1. Partial<Pick<T, 'id' | 'version'>>:从原类型中提取id和version字段,通过Partial将它们转为可选类型。
  2. 交叉类型&:把可选的id/version与处理后的其他字段合并,完整保留原类型的所有属性结构。
  3. 递归处理嵌套实体:对于其他字段,若该字段本身是Entity的子类,就递归应用PartialEntityIds,确保所有层级的id/version都被转为可选。

验证示例

用User类型测试:

type TransformedUser = PartialEntityIds<User>;

// 最终结构完全符合需求:
// {
//   id?: number;
//   version?: number;
//   name: string;
//   birthday: string;
//   address: PartialEntityIds<Address>; // 内部id/version已可选
//   department: PartialEntityIds<Department>; // 内部id/version已可选
// }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 13:45:38