When you use something like A extends B you are saying "I want to have something A that can be assigned to B".
What this means is that for typescript there are a lot of types that can be assigned to your interface I, you can see this with a simple example:
interface I {
foo?: number
}
type TrueOrFalse = {} extends I ? true : false // true
This means that typescript has no way to automatically detect that a type assignable to I will contains the foo property, indeed:
hasTypeError<{}>({})
works just fine. This is why i.foo will still be typed as number | undefined.