I’ve spent some time looking for solution so will write it here for the future when I will need to find it again =)
Imagine you have a generic component with 2 type variables:
const Component = <TObjectPreview, TObject>({
}: {
preview: TObjectPreview
onLoaded: (obj: TObject) => void
}) {
...
}
Pretty legitimate huh?
Now what if we are working with unions:
type SupportedPreview = PhotoPreview | VideoPreview
type SupportedObject = Photo | Video
and we want for consistency have always TObject = Photo
when TObjectPreview = PhotoPreview
and TObject = Video
when TObjectPreview = VideoPreview
?
Turns out we can do this with ternary operator in type definition + never
usage like this:
type ObjectForPreview<T> = T extends PhotoPreview
? Photo
: T extends VideoPreview
? Video
: never
const Component = <
TObjectPreview extends SupportedPreview,
TObject = ObjectForPreview<TObjectPreview>
>({
}: {
preview: TObjectPreview
onLoaded: (obj: TObject) => void
}) {
...
}
// Bonus: in the end user does not need to specify 2nd type variable
// Actually 1st one is also not needed - typescript does its magic based
// on supplied `preview` type.
Looks a bit hardcoded tbh but it solved my issue.
Ideally would be to use something more dynamic like Record<T1,T2>
but I could not understand how to do that.
If you know how to do this better — please let me know!