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

如何实现提取嵌套对象所有键的TypeScript联合类型?

解决TypeScript提取嵌套对象所有键的联合类型问题

问题分析

你尝试的两种递归实现存在以下问题:

  1. ExtractKeys无限递归:在TS4.5.5版本中,T extends Record<infer U, any>的条件依赖键类型推断,当处理嵌套的联合值类型时,TypeScript的类型系统会反复展开联合分支,超出编译器递归深度限制,触发TS2589错误。
  2. ExtractKeys2类型不准确:递归调用时误写为ExtractKeys而非ExtractKeys2,导致后续递归逻辑断裂,最终类型不符合预期。

正确实现方案

基础版(包含所有对象类型,包括数组)

// 示例类型,期望得到 'a' | 'b' | 'x' | 'c' | 'd'
type O = Record<'a', Record<'b' | 'x', Record<'c' | 'd', string | number>>>;

// 递归提取所有嵌套键的联合类型
type ExtractKeys<T> = 
  T extends object 
    ? keyof T | ExtractKeys<T[keyof T]> 
    : never;

// 验证:类型为 'a' | 'b' | 'x' | 'c' | 'd'
const validKey: ExtractKeys<O> = 'a'; // 正常
// const invalidKey: ExtractKeys<O> = 'z'; // 报错,符合预期

排除数组的版本(仅提取普通对象的键)

如果不需要提取数组的键(如length、数字索引等),可以增加数组过滤逻辑:

type ExtractKeys<T> = 
  T extends any[] 
    ? never 
    : T extends object 
      ? keyof T | ExtractKeys<T[keyof T]> 
      : never;

修正ExtractKeys2的笔误

将递归调用改为当前类型即可修复:

type ExtractKeys2<T> = T extends Record<string, any> ?
  keyof T | ExtractKeys2<T[keyof T]> : // 修正为ExtractKeys2
  never;

// 验证:类型正确
// const tryIt2: ExtractKeys2<O> = 'z'; // 报错,符合预期

核心思路

  • 用T extends object替代特定的Record判断,让类型系统更清晰地识别终止条件(遇到非对象类型时返回never)。
  • 确保递归调用的是当前定义的类型,避免笔误导致逻辑断裂。
  • 按需过滤数组等特殊对象类型,满足不同场景需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 23:45:37