首页 > 解决方案 > 基于另一个属性值的动态类型属性

问题描述

我正在制作一种类型来强制DynamicColor正确使用这种类型。

enum ColorsEnum {
  red = "red",
  green = "green",
  blue = "blue",
  yellow = "yellow",
}

type ColorsMapperType = {
  type: ColorsEnum
  red: {
    redProperty: string
  }
  green: {
    greenProperty: string
  }
  blue: {
    blueProperty: string
  }
  yellow: {
    yellowProperty: string
  }
}

type ColorsMapper = Omit<ColorsMapperType, "type">

export type DynamicColor = {
  [ColorType in keyof ColorsMapper]: {
    [Prop in 'type' | ColorType]: Prop extends 'type' ? ColorType : ColorsMapper[ColorType]
  }
}[keyof ColorsMapper]

Codesandbox:https ://codesandbox.io/s/naughty-sanderson-niqez?file=/src/index.ts

我大部分时间都在工作,但是我希望类型中的type字段DynamicColor是正确的ColorEnum类型。

现在,我得到了字符串值的自动完成ColorEnum,但不是实际的枚举类型。

例如,以下代码应该是有效的:

const color: DynamicColor = {
  type: ColorsEnum.green,
  green: {
    greenProperty: "1",
  },
}

以下代码均无效

const color0: DynamicColor = {
  type: "green", // invalid because not of ColorsEnum type
  green: {
    greenProperty: "1",
  },
}

const color1: DynamicColor = {
  type: ColorsEnum.blue, // invalid because property "blue" is not included
}

const color2: DynamicColor = {
  type: ColorsEnum.blue, // invalid because color property does not match correct type (ColorsEnum.blue should require a "blue" property)
  green: {
    greenProperty: "1",
  }
}

const color3: DynamicColor = {
  type: ColorsEnum.blue, // invalid because more than one color property is included
  blue: {
    blueProperty: "1",
  }
  green: {
    greenProperty: "1",
  }
}

有没有办法做到这一点?在此先感谢,如果还有其他方法可以改进此代码,我会全力以赴。

标签: typescript

解决方案


您基本上想将 中的所有项目映射ColorsEnum到另一种类型,例如 (pseudocode) { type: T; [T]: ColorsMapper[T] }。幸运的是,条件类型可以做到这一点。这是我找到的解决方案。

enum ColorsEnum {
  red = "red",
  green = "green",
  blue = "blue",
  yellow = "yellow",
}

type ColorsMapper = {
  type: ColorsEnum
  red: {
    redProperty: string
  }
  green: {
    greenProperty: string
  }
  blue: {
    blueProperty: string
  }
  yellow: {
    yellowProperty: string
  }
}
type MapToColorType<T> = T extends ColorsEnum ? { [key in T]: ColorsMapper[T] } & { type: T } : never;
type Result = MapToColorType<ColorsEnum>;

const color: Result = {
  type: ColorsEnum.green,
  green: {
    greenProperty: "1",
  },
}

你可以在这里玩弄它。

解释

问题是条件类型分布在联合类型上。这意味着该条件适用于工会的所有成员。枚举基本上是所有可能值的联合。我们可以利用它来将枚举的每个成员映射到特定类型。


推荐阅读