I have a discriminated union structure that I am working with:
type Union = {
// This is fascinating! The discriminant value can also be another union!
type: "foo" | "bar"
} | {
type: "baz"
} | {
type: "quux"
}
My goal is to enhance the type related to type: "baz"
by adding a new property, for example value: string
, resulting in something like this:
type ExtendedUnion = Extend<{
"baz": { value: string }
}> /* {
type: "foo" | "bar"
} | {
type: "bar"
} | {
type: "baz"
value: string
} */
The specific implementation of Extend
is just an example, but the ability to extend multiple types within the union simultaneously would be highly beneficial.
If the value is a union and the parameter is a value within that union (e.g.
Extend<{ "foo": { value: string } }>
), the output should be { type: "foo" | "bar"; value: string }
. Similarly, when extending both types in the union (e.g. Extend<{ "foo": { value: string }, "bar": { other: number } }>
), the result should be { type: "foo" | "bar"; value: string; other: number }
.
I have devised a utility type to achieve this, although it does not account for the case of
. This is how my type is structured:type: "foo" | "bar"
type Extend<TTypeOverride extends { [key in Union["type"]]?: unknown }> = {
[key in Union["type"]]:
// The Extract function is not handling the case when "key" is "foo" or "bar"
Extract<Union, { type: key }> &
(TTypeOverride[key] extends undefined ? unknown : TTypeOverride[key])
}[Union["type"]]
// Will not include { type: "foo" | "bar" }
type ExtendedUnion = Extend<{
quux: { value: string }
}> /* {
type: "baz"
} | {
type: "quux"
value: string
} */
As previously mentioned, the issue lies with the usage of Extract
and how it handles the
"foo" | "bar"
case. Any suggestions or pointers on how to address this?