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

TypeScript如何实现配置对象子属性oneOfKeys为父对象键名的类型约束

解决方案

核心思路是调整泛型推断优先级,让TS优先从配置对象的顶层键推断键名集合,再用这个集合约束所有oneOfKeys的取值。

可直接运行的代码实现

TS 4.9及以上版本推荐加const修饰符,避免字面量类型意外收窄:

// 泛型先接收完整配置对象类型,再自动约束内部oneOfKeys的取值范围
function testFunc<const T extends Record<string, { oneOfKeys: keyof T }>>(foo: T) {}

低版本TS去掉const修饰符即可:

function testFunc<T extends Record<string, { oneOfKeys: keyof T }>>(foo: T) {}

如果需要把父子类型单独抽离定义,可以写成:

interface ChildType<KeyNames extends string>  {
  oneOfKeys : KeyNames
}

type ParentType<T extends Record<string, any>> = {
  [K in keyof T]: ChildType<keyof T>;
};

function testFunc<const T extends ParentType<T>>(foo: T) {}

效果说明

用你提供的测试用例运行时,校验逻辑会完全符合预期:

  • 顶层的bal键不会再抛出错误,TS会正确推断顶层键集合为'foo' | 'bar' | 'bal'
  • bar属性的oneOfKeys: "baz"会抛出错误,因为baz不属于顶层键的集合

原写法问题原因

原来的写法中泛型参数KeyNames同时被顶层键、oneOfKeys两个位置作为类型来源,TS的泛型推断会收集所有位置的候选值合并为最终的泛型类型,不会优先采用顶层键的集合,所以oneOfKeys里的baz会被加入KeyNames的候选值,最终推断出的KeyNames是'foo' | 'bar' | 'baz',而顶层键bal不在这个集合里,就会抛出错误,和需求完全相反。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 23:36:04