如何让TypeScript对象的映射键仅存在于自身数组元素中?
问题解答
是否需要自引用类型?
是的,要实现mySpecificMapping的键只能是myArray中存在的枚举值这一约束,必须通过泛型结合自引用式的类型约束来实现。原代码里的普通接口无法让两个属性的类型动态关联,必须借助泛型建立myArray和mySpecificMapping的依赖关系。
实现方案
我们可以定义泛型类型来关联两个属性的取值范围,让mySpecificMapping的键只能是myArray中出现的枚举值:
enum ENUM_A { ONE="ONE", TWO="TWO", THREE="THREE", FOUR="FOUR" } // 泛型类型,T 代表 myArray 中允许的枚举值集合 type TYPE_A<T extends ENUM_A> = { myArray: T[], mySpecificMapping: { [K in T]?: boolean } } // 手动指定泛型参数,约束 mySpecificMapping 的键只能是 ONE/THREE const myObject: TYPE_A<ENUM_A.ONE | ENUM_A.THREE> = { myArray: [ENUM_A.ONE, ENUM_A.THREE], mySpecificMapping: { [ENUM_A.ONE]: true, // 取消下面这行注释会触发 TypeScript 错误 // [ENUM_A.TWO]: true, [ENUM_A.THREE]: true, // 取消下面这行注释会触发 TypeScript 错误 // [ENUM_A.FOUR]: true, } } // 用辅助函数自动推导泛型参数,无需手动指定 const createTYPE_A = <T extends ENUM_A>(obj: TYPE_A<T>) => obj; // 自动推导 T 为 ENUM_A.ONE | ENUM_A.THREE,非法键会直接报错 const myObject2 = createTYPE_A({ myArray: [ENUM_A.ONE, ENUM_A.THREE], mySpecificMapping: { [ENUM_A.ONE]: true, // [ENUM_A.TWO]: true, // 此处会立即触发类型错误 [ENUM_A.THREE]: true, // [ENUM_A.FOUR]: true, // 此处会立即触发类型错误 } });
原代码的问题
原接口TYPE_A中,myArray是任意ENUM_A元素组成的数组,mySpecificMapping允许所有ENUM_A成员作为键,两者没有类型关联。所以即使mySpecificMapping包含myArray中没有的键,TypeScript也不会判定为错误。
泛型约束的作用
这里的泛型T相当于把myArray的实际元素类型提取出来,再用这个类型去限制mySpecificMapping的键范围,本质上是让类型的两个属性形成自引用依赖——mySpecificMapping的合法键由myArray的取值决定,这种动态关联只有泛型能实现,普通接口无法做到。
内容的提问来源于stack exchange,提问作者Nathan Nguyen
相关产品推荐
相关产品推荐

