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

如何在NestJS的PickType中重命名选中的属性

扩展NestJS的PickType以支持属性重命名

我需要改造NestJS的PickType工具类型,使其支持在选取属性时对指定属性进行重命名,同时满足以下规则:

  • 规则1:如果重命名后的属性名在原类中已存在,且该属性也被选中,则抛出类型错误
  • 规则2:如果重命名后的属性名在原类中已存在,但未被选中,则正常生成重命名后的属性

原有PickType定义回顾

原PickType仅支持选取原类的属性,无法重命名:

interface Type<T = any> extends Function {
    new (...args: any[]): T;
}

declare function PickType<T, K extends keyof T>(classRef: Type<T>, keys: readonly K[]): Type<Pick<T, typeof keys[number]>>;

class AClazz {
  a: string;
  b: string;
  c: number;
}

const picked = PickType(AClazz, [
  'a',
 'c',
] as const);

// picked 的类型为 { a: string; c: number }

改造后的PickType实现

通过类型编程实现重命名支持与冲突校验,完整类型声明如下:

interface Type<T = any> extends Function {
  new (...args: any[]): T;
}

// 提取每个元素的原属性键(类型断言前的真实键)
type ExtractOriginalKey<T> = T extends `${infer K}` ? K : never;

// 提取每个元素的目标属性键(类型断言后的重命名键)
type ExtractTargetKey<T> = T extends infer U ? U : never;

// 校验重命名是否与已选中的原属性冲突
type ValidateRenameConflict<
  T,
  Keys extends readonly any[],
  OriginalKeys = ExtractOriginalKey<Keys[number]>,
  TargetKeys = ExtractTargetKey<Keys[number]>
> = Exclude<TargetKeys, OriginalKeys> extends infer RenamedKeys
  ? RenamedKeys extends keyof T
    ? RenamedKeys extends OriginalKeys
      ? never // 重命名后的键是原类中已被选中的属性,触发类型错误
      : unknown
    : unknown
  : unknown;

// 支持重命名的PickType
declare function PickType<
  T,
  Keys extends readonly any[],
  _ConflictCheck extends ValidateRenameConflict<T, Keys> = ValidateRenameConflict<T, Keys>
>(
  classRef: Type<T>,
  keys: Keys & readonly (keyof T | `${keyof T}`)[]
): Type<{
  [K in Keys[number] as ExtractTargetKey<K>]: T[ExtractOriginalKey<K>]
}>;

示例验证

基础重命名场景

将原类的c属性重命名为d,生成预期类型:

class AClazz {
  a: string;
  b: string;
  c: number;
}

const picked = PickType(AClazz, [
  'a',
  'c' as 'd',
] as const);

// picked 的类型为 { a: string; d: number }

规则1:重命名后属性已被选中,触发错误

当重命名后的属性d同时被作为原属性选中时,类型校验报错:

class AClazz {
    a: string;
    b: string;
    c: number;
    d: string;
}

// 类型错误:'d'已存在且被选中
const picked = PickType(AClazz, [
    'a',
   'c' as 'd',
   'd',
] as const);

规则2:重命名后属性存在但未被选中,正常生成

重命名后的属性d在原类存在但未被选中时,正常生成目标类型:

class AClazz {
    a: string;
    b: string;
    c: number;
    d: string;
}

const picked = PickType(AClazz, [
    'a',
   'c' as 'd',
] as const);

// picked 的类型为 { a: string; d: number }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 12:18:09