The challenge arises from the fact that when I extends Partial<Inner>
, it implies that I
can be a subtype of Partial<Inner>
. This means there are subtypes of Partial<Inner>
that, even after being passed through Required
, do not align with the I extends Inner
constraint on Foo
. An example of such a type is:
type Incompatible = Partial<Inner> & {a: undefined};
This is considered a valid subtype of Partial<Inner>
because the definition of Partial<Inner>
is {a?: string | undefined}
. However, applying Required<Incompatible>
does not transform it back into something that extends Inner
; instead, it merely results in {a: undefined}
. Trying to use this with Foo
like so will fail for similar reasons as your mapped type fails:
type Q = Foo<Required<Incompatible>>;
Playground link
To resolve this issue in a type-safe manner will depend heavily on your specific scenario. One might be tempted to utilize:
type RequiredInner<T extends Partial<Inner>> = {
[Key in keyof T]: T[Key] extends undefined ? Key extends keyof Inner ? Inner[Key] : never : T[Key];
};
...and then employ
Foo<RequiredInner<I>>
. While
it may work, but it assumes something significant that
might not hold true: There could exist a runtime value of
{a: undefined}
where you have that
Partial<Inner>
. This assumption lacks type safety. Therefore, we cannot provide a universal solution for addressing this in your actual code. Nevertheless, comprehending the problem should assist you in finding a resolution.