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

修复TypeScript的AddPostfixes泛型:实现动态添加属性后缀

解决TypeScript泛型添加指定后缀属性并继承可选性的问题

正确实现

以下是修复后的AddPostfixes泛型,可实现为原类型添加指定后缀的属性,同时保留原属性的可选性:

// 辅助类型:判断属性是否为可选
type IsOptional<T, K extends keyof T> = K extends keyof Required<T> ? false : true;

type AddPostfixes<T, Postfixes extends Record<string, unknown>> =
  // 保留原类型
  T &
  // 生成原属性为必选的后缀属性(必选)
  {
    [KP in `${keyof T & string}${keyof Postfixes & string}` as IsOptional<T, KP extends `${infer K}${string}` ? K : never> extends false ? KP : never]:
      KP extends `${infer K}${infer P}`
        ? K extends keyof T
          ? P extends keyof Postfixes
            ? Postfixes[P]
            : never
          : never
        : never
  } &
  // 生成原属性为可选的后缀属性(可选)
  {
    [KP in `${keyof T & string}${keyof Postfixes & string}` as IsOptional<T, KP extends `${infer K}${string}` ? K : never> extends true ? KP : never]?:
      KP extends `${infer K}${infer P}`
        ? K extends keyof T
          ? P extends keyof Postfixes
            ? Postfixes[P]
            : never
          : never
        : never
  };

实现说明

  1. 生成后缀属性:通过模板字符串类型${keyof T & string}${keyof Postfixes & string},遍历原类型所有属性与所有后缀的组合,生成新的属性名。
  2. 绑定对应类型:对每个组合的属性名,解析出原属性名K和后缀P,返回Postfixes[P]作为该属性的类型,确保每个后缀对应正确的类型。
  3. 继承可选性:通过IsOptional辅助类型判断原属性是否为可选,分别生成必选/可选的后缀属性,保证新属性的可选性与原属性一致。

验证效果

示例1:全可选原类型

type OriginalType = {
  name?: string;
  age?: number;
};

type ModifiedType = AddPostfixes<
  OriginalType,
  { Postfix1: number; Postfix2: string; Postfix3: boolean }
>;

// 最终类型符合预期:
// {
//   name?: string;
//   age?: number;
//   namePostfix1?: number;
//   namePostfix2?: string;
//   namePostfix3?: boolean;
//   agePostfix1?: number;
//   agePostfix2?: string;
//   agePostfix3?: boolean;
// }

示例2:混合可选/必选原类型

type MyOriginalType = {
  name: string;
  age?: number;
};

type PostfixedType = AddPostfixes<MyOriginalType, { Postfix1: number; Postfix2: string; Postfix3: boolean }>;

// 最终类型:
// {
//   name: string;
//   age?: number;
//   namePostfix1: number;
//   namePostfix2: string;
//   namePostfix3: boolean;
//   agePostfix1?: number;
//   agePostfix2?: string;
//   agePostfix3?: boolean;
// }

原实现问题分析

  1. 逻辑颠倒:原实现试图从原属性名中解析后缀,而非从生成的新属性名中拆分原属性与后缀,导致类型匹配错误。
  2. 类型绑定错误:返回的是原属性类型或所有后缀类型的联合值,未对应到具体后缀的类型。
  3. 未处理可选性:未继承原属性的可选状态,导致后缀属性的可选性不符合预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 06:50:29