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

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>
}

然后创建一个对象,其中根据TypeMap验证objData的类型:

myObj:SecondaryInterface = {value:"", objChosen:{obj:MyEnum.A, objData:"a string"}}

这在一定程度上是可行的,但是当我输入objData时,它给出一个联合类型提示‘字符串|数字’,而不仅仅是‘字符串’,因为它从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.但这不是你想要的.你希望在TObjInterface<T>distribute除以unions,所以ObjInterface<MyEnum.A | MyEnum.B>的计算结果是ObjInterface<MyEnum.A> | ObjInterface<MyEnum.B>.有不同的方法来实现这一点,比如使用distributive conditional types,但当你想要分发的东西是像键一样的时候,我通常更喜欢写一个distributive object type,就像microsoft/TypeScript#47string | number中创造的那样.那是你index intoA mapped type的地方.

如果你有一个类键类型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继续为generic,如果你所关心的是在那里插入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 link to code

Typescript相关问答推荐

属性的类型,该属性是类的键,其值是所需类型

类型脚本接口索引签名

泛型和数组:为什么我最终使用了`泛型T []`而不是`泛型T []`?<><>

`((PrevState:NULL)=>;NULL)|null`是什么意思?

如何在使用`Next—intl`和`next/link`时导航

在TypeScrip的数组中判断模式类型

返回具有递归属性的泛型类型的泛型函数

通过字符串索引访问对象';S的值时出现文字脚本错误

是否存在类型联合的替代方案,其中包括仅在某些替代方案中存在的可选属性?

我可以使用TypeScrip从字符串词典/记录中填充强类型的环境对象吗?

垫表页脚角v15

TypeScrip:使用Union ToInterval辅助对象,但保留子表达式

ANGLE NumberValueAccessor表单控件值更改订阅两次

带投掷的收窄类型

抽象类对派生类强制不同的构造函数签名

React-跨组件共享功能的最佳实践

如何使用动态生成的键和值定义对象的形状?

从 npm 切换到 pnpm 后出现Typescript 错误

为什么我的 Typescript 函数中缺少 void 隐式返回类型?

React 中如何比较两个对象数组并获取不同的值?