Resolving Discriminated Union Types with an Intersection
The best way to approach this is by using an intersection. Initially, the code looks like this:
type ModalProps = | { variant: "no-title" } | ({ variant: "title" title: string } & { buttonColor: string })
However, saving the file will cause
Transcript
00:00 The best way to do this then is by using an intersection. And the intersection kind of looks like this, where we use this ampersand symbol and add in button color string here. Now, if we save this file, then Prettier is actually gonna kind of screw us over a little bit. Because if you notice,
00:17 the way that it places these brackets here, these parentheses, is actually like only attaching button color into one branch here. And we can see this if we go into our component itself. So we're on the title variant. And now if we're inside no title, it's actually erring at us
00:36 because it doesn't exist on type variant no title. So we need a way to basically say to TypeScript, actually, I want to attach this to both variants. So even without the parentheses, actually, if you look at the operational order, TypeScript is correct, or Prettier is correct here,
00:54 because and actually goes before or in the operation order. This means that this gets resolved as one type and it's behaving exactly the same as you can see below, even without the brackets. And this gets resolved as a separate member of the union. So the only way to properly solve this is by bracketing up the entire union.
01:13 So wrapping these in parentheses, and yes, this is valid syntax, having kind of this just sort of floating before the union. And if we save this, then it's gonna properly format it. And you can see that this is a type and then this gets intersected with it. So now button color gets applied to each member of the union.
01:31 And it means that we have button color on here. And it means that all of these tests are passing below too. So this is, even though this looks a little bit ugly, this is the smoothest way to do it. And it's actually the way it formats it, it's nice and clear kind of which union is being intersected with which. You could even, if you wanted to take this out
01:51 and say my little props is, let's just leave it like that for now. And let's say, variant modal props. You could add that as kind of like a second declaration there and then add that in variant modal props. And now the modal props reads a little bit easier too. So you don't need to use this parentheses pattern,
02:11 but that's kind of what's happening under the hood, right? We're just sort of attaching, like using this alias to attach them in parentheses and then intersecting it with the button color and we're good to go. So this might be the best way to go if you're aiming for code readability, but both work equally well.