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

如何限制TypeScript递归可索引类型的每层属性数量为恰好一个?

如何限制TypeScript递归可索引类型的每层属性数量为恰好一个?

嘿,我懂你的需求了——你现在有个递归的TypeScript类型SimpleUpdateCondition,但希望每一层的对象都只能有刚好一个属性,原来的类型允许任意多键,确实没法满足这个限制,咱们来调整下它。

其实核心思路就是给每一层的对象加上“只能有单个任意键”的约束,同时保留原来的递归结构。我给你两种可行的写法,你可以按需选:

写法一:用工具类型封装约束

先定义一个工具类型,专门用来确保对象恰好只有一个属性,然后把它和你的递归结构结合:

// 工具类型:确保对象恰好只有一个属性
type ExactlyOneProperty<T> = {
  [K in keyof T]: T[K]
} & {
  // 多余的键会被约束为never,赋值就会报错
  [ExtraKey in Exclude<string, keyof T>]?: never;
};

// 重构后的递归类型
type SimpleUpdateCondition = 
  | string 
  | ExactlyOneProperty<{
      [key: string]: SimpleUpdateCondition | [string, SimpleUpdateCondition]
    }>;

写法二:直接交叉类型约束(更简洁)

如果不想额外定义工具类型,也可以直接把约束逻辑写在递归类型里,用交叉类型实现:

type SimpleUpdateCondition = 
  | string 
  | {
      [key: string]: SimpleUpdateCondition | [string, SimpleUpdateCondition]
    } & {
      // 这个签名会让多余的属性触发类型错误
      [extraKey: string]: never;
    };

咱们来测试下效果:

  • 合法的示例(每层只有一个属性):

    const validCondition: SimpleUpdateCondition = {
      user: {
        age: ["gt", "18"]
      }
    };
    

    这个完全没问题,符合类型要求。

  • 非法的示例(某一层有多个属性):

    // ❌ 这里会报错,因为user层有两个属性,多余的name会触发never类型冲突
    const invalidCondition: SimpleUpdateCondition = {
      user: {
        name: "Alice",
        age: ["gt", "18"]
      }
    };
    

原理其实很简单:利用TypeScript的类型交叉特性,把“允许单个任意键的对象”和“所有键都是never的对象”交叉到一起。这样如果你定义了多个键,除了第一个之外的键都会被推断为never类型,和你实际赋值的类型不匹配,自然就会抛出错误,完美实现了“每层恰好一个属性”的限制。

备注:内容来源于stack exchange,提问作者Peter S

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 17:03:21