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

TypeScript泛型嵌套属性类型推断:类型保留与字面量值问题

对象嵌套键下划线转换的类型修复方案

问题背景

需要实现对象结构转换:仅给嵌套对象的键添加前缀下划线,例如将{ isElevated: { sm: true, xl: 'false' }, color: 'green' }转为{ isElevated: { _sm: true, _xl: 'false' }, color: 'green' }。现有代码存在两个核心问题:

  • 处理嵌套属性时丢失类型信息;
  • 值类型被自动拓宽(如字面量'green'被推断为宽泛的string类型),希望无需手动添加as const就能保留原始字面量类型。

修复后的代码实现

// 定义转换类型:仅给一层嵌套对象的键添加下划线(如需深层转换可改为递归)
type TransformProps<T> = {
  [K in keyof T]: T[K] extends object
    ? {
        [NK in keyof T[K] as `_${string & NK}`]: T[K][NK];
      }
    : T[K];
};

// 转换函数:自动推断字面量类型,修复嵌套属性类型丢失问题
function transform<T extends object>(props: T): TransformProps<T> {
  const transformed: Partial<TransformProps<T>> = {};

  for (const key in props) {
    if (Object.prototype.hasOwnProperty.call(props, key)) {
      const value = props[key];
      // 处理嵌套对象(排除null,因为typeof null === 'object')
      if (typeof value === 'object' && value !== null) {
        const nestedTransformed: Record<string, unknown> = {};
        for (const nestedKey in value) {
          if (Object.prototype.hasOwnProperty.call(value, nestedKey)) {
            nestedTransformed[`_${nestedKey}`] = value[nestedKey];
          }
        }
        // 类型断言确保转换后的嵌套结构符合TransformProps定义
        transformed[key as keyof TransformProps<T>] = nestedTransformed as TransformProps<T>[keyof TransformProps<T>];
      } else {
        // 直接赋值非嵌套属性,保留原始类型
        transformed[key as keyof TransformProps<T>] = value as TransformProps<T>[keyof TransformProps<T>];
      }
    }
  }

  return transformed as TransformProps<T>;
}

// 测试示例
const result = transform({
  isElevated: { sm: true, xl: 'false' },
  color: 'green',
});

const success1 = result.isElevated["_sm"] === true; // 类型校验通过,无报错

// 现在这些错误会被TypeScript正确捕获
const fail1 = result.isElevated["_sm"] === false; // TS报错:类型“true”不能赋值给类型“false”
const fail2 = result.color === "red"; // TS报错:类型“"green"”不能赋值给类型“"red"”

关键修复点说明

  1. 自动保留字面量类型
    调整函数泛型为T extends object,让TypeScript直接基于传入的对象字面量推断精确的字面量类型,无需手动添加as const强制约束。

  2. 解决嵌套属性类型丢失

    • 替换reduce为for...in循环,更直观地逐个处理每个属性,避免类型推断模糊;
    • 对嵌套对象的转换结果使用类型断言,确保其与TransformProps定义的类型结构完全对齐;
    • 用Object.prototype.hasOwnProperty.call过滤原型链属性,避免遍历到非目标属性导致类型混乱。

扩展:支持深层嵌套转换

如果需要对多层嵌套对象的键都添加下划线,可以将TransformProps改为递归类型:

type TransformProps<T> = {
  [K in keyof T]: T[K] extends object
    ? TransformProps<{ [NK in keyof T[K] as `_${string & NK}`]: T[K][NK] }>
    : T[K];
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 23:45:41