I am making a type to enforce that this DynamicColor type is used correctly.
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
I have it mostly working, however I want the type field in the DynamicColor type to be the correct ColorEnum type.
Right now, I get autocomplete for the string values of ColorEnum, but not the actual enum type.
For example, the following code should be valid:
const color: DynamicColor = {
type: ColorsEnum.green,
green: {
greenProperty: "1",
},
}
None of the following code should be valid
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",
}
}
Is there a way to do this? Thanks in advance, and if there are other ways to improve this code I'm all ears.
typein aColorMapperobject isblue, the only property it has isblue? I.e. you're discriminating the fields by thetype? If so, you could just make separate types for the correct type-to-property combo and create an union type: typescriptlang.org/docs/handbook/…ColorsMapperTypetype (I renamed it fromColorMapper) has constraints in our domain and needs to stay as the same model. I'm hoping to do this without changing that type at all. Specifically, the type is being used as a GraphQL input type. GraphQL doesn't allow union input types, so we needed to resort to something like what I have above.