My discriminated union is quite basic, but I want to restrict the discriminator to only allow specific values that come from another string literal union type. This would simplify the process of adding new "cases" to the discriminated union.
Here is a string literal union describing the permitted "values" for the type:
type AllowedType = "typeForNumber" | "typeForBoolean"
The data type I use describes the data using that string literal union:
type Data = {
type: AllowedType,
value: number | boolean
}
In my example, there are two options where the value
field can have a more specific type based on the type
field. Although these options are not utilized in practice, they serve as demonstrations:
// Option 1 - "value" is a "number"
type DataOption1 = {
type: "typeForNumber",
value: number
}
// Option 2 - "value" is a "boolean"
type DataOption2 = {
type: "typeForBoolean",
value: boolean
}
What I actually aim to achieve is a discriminated union for Data
, allowing me to specify more precise types for its value
field:
type Data =
| {
type: "typeForNumber"
value: number
}
| {
type: "typeForBoolean"
value: boolean
}
When utilizing this type, everything functions correctly:
const myData: Data = {
type: "typeForNumber",
// this will trigger an error as it should be a `number`
value: "some string"
}
My question is: How can I ensure that the type
field in my Data
type is restricted to the options in the AllowedType
?
As additional options for AllowedType
may arise in the future, I wish to confine the possible union types accordingly.
One could add another union to the Data
type without encountering any errors:
type Data =
| {
type: "typeForNumber"
value: number
}
| {
type: "typeForBoolean"
value: boolean
}
| {
type: "someOtherType"
value: string
}
However, this new union (with type: "someOtherType"
) should not be allowed.
Is it feasible to restrict the discriminator (type
) within this discriminated union (Data
) to follow the guidelines set by another string literal union type (AllowedType
)?
Although I attempted to utilize a wrapper within the intersection, the unions appear to disregard (or overwrite) the type
definition:
type AllowedType = "typeForNumber" | "typeForBoolean"
type DataWrapper = {
type: AllowedType
value: number | boolean
}
type Data = DataWrapper &
(
| {
type: "typeForNumber"
value: number
}
| {
type: "typeForBoolean"
value: boolean
}
)