-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
(🐞) No error when overload implementation has incompatible return type #12401
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Not sure why this should be an error. |
@JelleZijlstra It's not to do with the implementation, class A:
def foo(self) -> int: ...
class B(A):
def foo(self) -> object: ... In the OP only subtypes of |
I think this is intentional, as there is no way to correctly annotate an overload like the following due to overload signatures being intersections in the return type. The following: from typing import overload
@overload
def foo(a: int) -> int: ...
@overload
def foo(a: str) -> str: ...
def foo(
a: int | str # correct
) -> int | str: ... # incorrect, should be intersection of int and str It is at least, much more close to being correct, and I would expect mypy to enforce this tighter(unionized) type. That being said, the true nature of overloads is far more complicated than just unionizing the inputs and intersecting the outputs, their final form is a complex conditional type with no currently existing method of describing or checking them. |
i believe this is related to microsoft/TypeScript#47669. specifically, the issue is that the function implementation is not checked to be assignable to its type (the overloads). in typescript, function interfaces/intersections can be used to create overloads on arrow functions as they do not have their own dedicated overload syntax, however this results in so many false positives that it's pretty much unusable. take this example: // Type '(value: string | number) => string | number' is not assignable to type '{ (value: number): number; (value: string): string; }'.
// Type 'string | number' is not assignable to type 'number'.
// Type 'string' is not assignable to type 'number'
const foo: {
(value: number): number
(value: string): string
} = (value) => value there are two workarounds for this, both of which are pretty annoying: const foo: {
(value: number): number
(value: string): string
} = (value: number | string) => value as number & string or more accurately (which almost defeats the point of the overload in the first place): const foo: {
(value: number): number
(value: string): string
} = <T extends number|string>(value: T): T => value so i'm skeptical of making overloads work this way. while it is stricter, it makes overloads pretty much unusable in most cases (in typescript it's not as much of a problem because you can get around it with generics and conditional types for some of the more complicated overloads) i think @KotlinIsland's idea of enforcing that the impl's return type is at least a union of the return types in the overloads is a decent compromise tho |
This is almost identical to a constrained T = TypeVar("T", int, str)
def foo(value: T) -> T:
return value |
Uh oh!
There was an error while loading. Please reload this page.
playground
While the strictest of solutions would be to enforce the return type be an intersection of the overload return types, that would result in being overly strict to the point of being unusable. I suggest enforcing the return type to be a union of the overloads, this is not typesafe, but is much safer than not checking it at all.
The text was updated successfully, but these errors were encountered: