如何构建TypeScript接口实现基于模型对象的类型约束
解决TypeScript中Command接口的类型约束问题
最终实现方案
通过映射类型生成联合类型,自动生成所有合法的table与attribute对应组合,无需手动传入泛型参数,同时严格约束类型匹配:
interface ModelA { label: string } interface ModelB { name: string } interface Models { A: ModelA B: ModelB } // 遍历Models的所有键,生成对应的合法Command类型,再合并为联合类型 type Command = { [K in keyof Models]: { table: K attribute: keyof Models[K] } }[keyof Models] // 直接使用即可,类型约束完全生效 const commands: Command[] = [ { table: 'A', attribute: 'label' }, // 合法 { table: 'B', attribute: 'name' }, // 合法 // 以下代码会触发类型错误,符合预期 // { table: 'A', attribute: 'name' }, // { table: 'C', attribute: 'xxx' }, ]
为什么之前的方案行不通?
泛型必须传参的问题:
最初的Command<Model extends keyof Models>需要手动指定泛型参数,用Command<any>会完全失去类型约束,违背需求。泛型默认值的问题:
当给泛型设置默认值Model = keyof Models时,TypeScript会将Model视为联合类型'A' | 'B',此时Models[Model]是ModelA | ModelB,但TypeScript无法在单个接口中关联table和attribute的对应关系——它无法判断当前table是'A'还是'B',因此无法约束attribute必须匹配对应模型的属性,甚至会抛出索引类型错误。
可选:保留泛型版本(用于指定具体Model的场景)
如果需要单独创建指定某类Model的Command,可以同时保留泛型接口,再基于它生成联合类型:
// 泛型接口,用于单个指定Model的场景 interface CommandGeneric<Model extends keyof Models> { table: Model attribute: keyof Models[Model] } // 自动生成所有合法组合的联合类型 type Command = CommandGeneric<keyof Models>[keyof Models] // 单个指定Model的用法 const aCommand: CommandGeneric<'A'> = { table: 'A', attribute: 'label' }
内容的提问来源于stack exchange,提问作者bhutchins
相关产品推荐
相关产品推荐

