Closed
Description
I am trying to customize a function that takes an object of a union type and accesses different attributes depending on the type. The type of the object is specified by a type
attribute.
from typing import Union
from dataclasses import dataclass
TEXT = 'TEXT'
IMAGE = 'IMAGE'
@dataclass
class TextMessage:
text: str
type = TEXT
@dataclass
class ImageMessage:
url: str
type = IMAGE
def output(message: Union[TextMessage, ImageMessage]) -> None:
if message.type == TEXT:
print(message.text)
Mypy does not like this, saying:
error: Item "ImageMessage" of "Union[TextMessage, ImageMessage]" has no attribute "text"
And I understand it. I am trying to guess one attribute based on the value of another one. This is poor engineering.
However, the same thing works in other languages, for example, in JS Flow:
// @flow
type TextMessage = {
type: 'TEXT',
text: string
};
type ImageMessage = {
type: 'IMAGE',
url: string
};
function output(message: TextMessage | ImageMessage) {
if (message.type === 'TEXT') {
console.log(message.text);
}
}
Live Flow link: here
So the question is, is there a way to make mypy understand my conditions? Maybe using Literal
types? I tried to figure this out but the docs are a bit confusing.
P.S. I can always do if isinstance(message, TextMessage)
and this will satisfy mypy, but putting lots of isinstance()
in my code seems even more hacky.