首先,创建一个类型,将枚举键与类型相关联:
enum MyEnum {
A,
B
}
type TypeMap = {
[MyEnum.A]:string,
[MyEnum.B]:number
}
interface ObjInterface<T extends keyof TypeMap> {
obj: T,
objData: TypeMap[T]
}
interface SecondaryInterface {
value: string,
objChosen: ObjInterface<keyof TypeMap>
}
然后创建一个对象,其中 objData 的类型根据 TypeMap 进行验证:
myObj:SecondaryInterface = {value:"", objChosen:{obj:MyEnum.A, objData:"a string"}}
这部分有效,但是当我输入 objData 时,它给出了联合类型提示 'string |数字”而不仅仅是“字符串”,因为它从 keyof TypeMap 推断类型而不是确切的 TypeMap[T]。
是否有可能获得所使用的枚举键及其在类型映射中设置的关联类型的精确类型匹配?
它可以使用类型断言来工作,但是可以在没有类型断言的情况下工作吗?:
myObj:SecondaryInterface = {value:"", objChosen:<ObjInterface<MyEnum.A>>{obj:MyEnum.A, objData:"a string"}}
根据您的定义,
ObjInterface<MyEnum.A | MyEnum.B>
是单个对象类型,其中obj
可以是任何MyEnum
,objData
可以是string | number
。但这不是你想要的。您希望 ObjInterface<T>
distribute over T
中的 unions,以便
ObjInterface<MyEnum.A | MyEnum.B>
被评估为 ObjInterface<MyEnum.A> | ObjInterface<MyEnum.B>
。有不同的方法可以实现这一点,例如使用分布式条件类型,但是当您想要分配的东西类似于键时,我通常更喜欢编写分布式对象类型,如microsoft/TypeScript#47109中所创造的那样。这就是您索引到映射类型的地方。
如果您有一个类似键的类型
K
,并且想要将类型函数 F<K>
分布在 K
中的联合上,那么您可以编写 {[P in K]: F<P>}[K]
。这会变成一种映射类型,其中 K
的每个成员都有一个属性,该映射类型会立即使用 K
进行索引以形成这些属性的并集。
对于您的代码,如下所示:
type ObjInterface<K extends keyof TypeMap> = {
[P in K]: {
obj: P,
objData: TypeMap[P]
}
}[K]
然后
ObjInterface<keyof TypeMap>
计算为
/* type ObjInterface<keyof TypeMap> = {
obj: MyEnum.A;
objData: string;
} | {
obj: MyEnum.B;
objData: number;
} */
interface
,所以也许应该更改名称。
当然,此时您实际上还没有说明为什么需要
ObjInterface
继续保持 通用,如果您关心的只是插入 keyof TypeMap
的话。如果您不需要通用的,您可以将 K
硬编码为 keyof TypeMap
并制作它
type ObjInterface = { [K in keyof TypeMap]: {
obj: K,
objData: TypeMap[K]
} }[keyof TypeMap]
然后剩下的代码是
interface SecondaryInterface {
value: string,
objChosen: ObjInterface
}
const myObj: SecondaryInterface =
{ value: "", objChosen: { obj: MyEnum.A, objData: "a string" } }; // okay
myObj.objChosen = { obj: MyEnum.B, objData: 123 }; // okay
myObj.objChosen = { obj: MyEnum.A, objData: 123 }; // error
随心所欲。