There has been much discussion about typing discriminated unions, but I have not found a solution for my specific case yet. Let's consider the following code snippet:
type A = {label: 'a', options: {x: number}; text: string}; // label serves as a tag
type B = {label: 'b', options: {y: string}; text: string};
type C = A | B;
type D<T extends C> = {
label: T['label'];
displayOptions: T['options'];
complexValue: T extends B ? T['options']['y'] : never;
};
function f<U extends D<C>>(u: U) {
if (u.label === 'a') {
u.displayOptions // should be inferred as {x: number} only
}
}
At this point, one would expect the type of u.displayOptions
to be specifically {x: number}
due to the nature of the "tag" provided by the label
. However, the issue still persists and the type remains as {x: number} | {y: string}
.
The root of this problem could lie in the way D
is defined, where T['label']
and T['options']
are indirectly referenced. For instance, utilizing a property like type: T
in D
, followed by if (t.type.label === 'a')
seems to work.
Unfortunately, this alternative approach is not practical for the following reasons:
- I wish to avoid including all properties of
T
(orC
) inD
(e.g., excludingtext
). - The desired properties may undergo renaming (e.g., from
options
todisplayOptions
). - Addition of properties dependent on
T
, likecomplexValue
, is necessary.
Is there a simple solution available that can fulfill these requirements?