Search code examples
pythonmypypython-typingself-type

How to resolve "Incompatible return value type (got "FancyCat", expected "Self")"


Here's a minimal example I've written:

from __future__ import annotations

from typing import Protocol
from typing_extensions import Self


class Cat(Protocol):
    def add(self, other: Self) -> Self:
        ...
    def sub(self, other: Self) -> Self:
        ...


class FancyCat(Cat):
    def __init__(self, value: int):
        self._value = value

    def add(self, other: Self) -> Self:
        return FancyCat(self._value + other._value)

    def sub(self, other: Self) -> Self:
        return FancyCat(self._value - other._value)

fc = FancyCat(3)
fc2 = FancyCat(4)
fc.add(fc2)

If I try to type check it, I get

$ mypy t.py
t.py:19: error: Incompatible return value type (got "FancyCat", expected "Self")  [return-value]
t.py:22: error: Incompatible return value type (got "FancyCat", expected "Self")  [return-value]
Found 2 errors in 1 file (checked 1 source file)

I'm so confused - isn't Self FancyCat in this case?

How can I satisfy mypy here?


Solution

  • Your code does not guarantee that Self will be returned. For example, child classes will still return FancyCat, therefore Self annotation is invalid.

    To get rid of errors, you can either:

    a) make sure it's always self.__class__ returned, which IS actual Self

    def add(self, other: Self) -> Self:
        return self.__class__(self._value + other._value)
    

    b) type with what you are actually returning, FancyCat

    def sub(self, other: Self) -> FancyCat:
        return FancyCat(self._value - other._value)