如何在 Typescript 中的嵌套对象内使用类型映射?

问题描述 投票:0回答:1

首先,创建一个类型,将枚举键与类型相关联:

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"}}
typescript types enums typemaps
1个回答
0
投票

根据您的定义,

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

随心所欲。

Playground 代码链接

© www.soinside.com 2019 - 2024. All rights reserved.