如何在TypeScript中实现Options类型的联合键约束?
TypeScript约束item为obj1或obj2的键的实现方案
你遇到的问题根源在于TypeScript的泛型推断优先级:原代码中t1和t2的推断会优先匹配item的类型,而不是先从obj1、obj2的键推断泛型。当传入item: 'white'时,TypeScript会认为t1 | t2 = 'white',进而将t1和t2都推断为'white',导致obj1的键被限制为'white',与实际传入的red、green冲突,所以报错。
方案1:用泛型捕获obj1和obj2的完整类型
直接让泛型参数捕获obj1和obj2的具体类型,再通过keyof约束item的取值范围:
declare function f<T1 extends Record<string, any>, T2 extends Record<string, any>>( opts: { obj1: T1; obj2: T2; item: keyof T1 | keyof T2 } ): void; // 符合预期,无报错 f({ obj1: { red: null, green: null }, obj2: { black: null, white: null }, item: 'white' }); // 非法输入会触发类型错误(item不在允许的键中) f({ obj1: { red: null }, obj2: { black: null }, item: 'blue' // 类型错误:"blue"不能赋值给"red" | "black" });
方案2:用交叉类型约束单一泛型参数
如果希望用单一泛型参数,也可以通过交叉类型将obj的类型与item的约束结合:
declare function f<O extends { obj1: Record<string, any>, obj2: Record<string, any> }>( opts: O & { item: keyof O['obj1'] | keyof O['obj2'] } ): void; // 同样可以正常工作 f({ obj1: { red: null, green: null }, obj2: { black: null, white: null }, item: 'white' });
为什么这两种方案可行?
这两种方案都改变了泛型推断的顺序:TypeScript会先推断obj1和obj2的具体类型(或泛型O的结构),再基于这些类型推导item的合法取值范围,完全符合你预期的逻辑——先确定obj1、obj2的键,再约束item必须是其中之一。
内容的提问来源于stack exchange,提问作者UndefinedBehavior
相关产品推荐
相关产品推荐

