Create a Discriminated Union through Intermediary Transformations
The solution here is pretty dense and looks a little complicated:
type MutuallyExclusive<T> = { [K in keyof T]: Record<K, T[K]>;}[keyof T];
Let's work through it by going back to first principles, and checking our work by hovering over ExclusiveAttributes
:
type ExclusiveAtt
Transcript
0:00 The solution here is pretty dense and complicated. You can see this mutually exclusive type. We're obviously doing a mapping type, and we've quite a lot of annotations here. Let's remove a bit of this and go back to first principles.
0:14 If we just start from this setup, which we've seen before, then what we're going to end up with is it's going to remap over attributes and return them to us.
0:26 Starting from here, we know that in order to create a union, we want to create an intermediary representation of that union in an object, and then remap over that object in order to get back our proper union values. That's the way to do it.
0:44 The members of this union that we want are what we want to stick in this slot there, which is in the value. Let's say Record<T>, and let's just say...In fact, it's going to be K, and let's actually just make an empty object here. I'm going to say const example is ExclusiveAttributes. Let's just see what this is here.
1:07 What this is doing now is it's basically saying, for each of the properties, I'm going to create a record where it has one key, which is id in our username, and then we're going to parse something random into that. Currently, we're just parsing an empty object.
1:25 I can do this with email, id, id, and then username, username, username. Each of these, we don't want to parse this here actually. We want this to represent the value of the thing inside attributes. That means we can say T K.
1:41 T then is going to be this thing we're parsing in, which is attributes, and the K is the index or the key that we're currently on. This means that each of these then is going to end up being a string, because that's how they're typed inside attributes.
1:56 That's pretty good. We're getting there, but now we've got each of these available to us, we just need to map over id, email, and username to grab the members of the union. For that, we say keyof T, and now the example that we get at the end is going to be email, blah, blah, blah. That's going to be enough to parse this.
2:17 The cool thing about this is that I have to parse one of these. This is really nice for like form handlers and things like these, where you have to at least parse one, so we have line of id and that makes it parse.
2:31 This is pretty cool. We end up with this record of id string, or record email string, or record username string.