In practice, this would be solved with `typing.overload`[0].
Using you example:
from typing import overload
@overload
def fooify(x: int) -> int:
...
@overload
def fooify(x: list[int]) -> list[int]:
...
def fooify(x: list[int] | int) -> list[int] | int:
if isinstance(x, list):
return [fooify(_x) for _x in x]
return x * 2
[0] https://docs.python.org/3/library/typing.html#overload