如何限制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
相关产品推荐
相关产品推荐

