The easiest way to do this is probably to use a mapped type with renamed keys like this:
type InvitationMap = { [T in Invitation as NonNullable<T['__typename']>]: T }
Here we are iterating the type T over the union members of Invitation. For each such member T we want the property value to be T, and we want the property key to be the string literal type of T's __typename property. That would just be T['__typename'] using indexed access, but that doesn't quite work. Because the __typename property is optional, the property type will include undefined (like 'ClientInvitation' | undefined or 'ExpertInvitation' | undefined). To remove undefined quickly we can use the NonNullable<T> utility type.
Let's look at the IntelliSense quick info for the InvitationMap type:
/* type InvitationMap = {
ClientInvitation: {
__typename?: "ClientInvitation" | undefined;
email: string;
hash: string;
organizationName: string;
};
ExpertInvitation: {
__typename?: "ExpertInvitation" | undefined;
email: string;
hash: string;
expertName: string;
};
} */
Now that we have InvitationMap, we can just index into it with the desired key:
type ClientInvitation = InvitationMap['ClientInvitation'];
/* type ClientInvitation = {
__typename?: "ClientInvitation" | undefined;
email: string;
hash: string;
organizationName: string;
} */
Playground link to code
SomeTypeUtil['ClientInvitation']? Or would a normal generic type utility likeSomeTypeUtil<'ClientInvitation'>be acceptable? You can actually do it either way, but it's a little weird to expect that indexed access would be possible. Is this just a typo?