Python Types for Union of String Literal and Other Type

I wanted to add a single special value to another type for a union type, something like this:

from typing import Literal
                                                                            
UNMEASURED = "unmeasured"                                                    
Unmeasured = Literal[UNMEASURED]
Resource = int | Unmeasured

notes: dict[Resource, str] = {1: "foo", 2: "bar", 3: "baz", UNMEASURED: "quux"}
resources = [1, 2, 3] + [UNMEASURED]
for resource in resources:
    print(notes[resource])

This works, but mypy complains: ‘error: Parameter 1 of Literal[…] is invalid [valid-type]’. So to make this pass mypy typechecking you have to repeat “unmeasured” as a literal. Even if you do that:

from typing import Literal

UNMEASURED = "unmeasured"
Unmeasured = Literal["unmeasured"]
Resource = int | Unmeasured

notes: dict[Resource, str] = {1: "foo", 2: "bar", 3: "baz", UNMEASURED: "quux"}
resources = [1, 2, 3] + [UNMEASURED]
for resource in resources:
    print(notes[resource])

mypy will complain: ‘Dict entry 3 has incompatible type “str”: “str”; expected “int | Literal[‘unmeasured’]”: “str” [dict-item]’ and also ‘Invalid index type “str | int” for “dict[int | Literal[‘unmeasured’], str]”; expected type “int | Literal[‘unmeasured’]” [index]’

Eventually I came up with:

from enum import Enum
from typing import Literal

class Aspect(Enum):
    UNMEASURED = "unmeasured"

Resource = int | Aspect

notes: dict[Resource, str] = {1: "foo", 2: "bar", 3: "baz", Aspect.UNMEASURED: "quux"}
resources = [1, 2, 3] + [Aspect.UNMEASURED]
for resource in resources:
    print(notes[resource])

which both produces the same result, and passes the typechecker. I don’t love the weird Enum hanging out on its own but it does at least put the magic string in one place only and pass. I wonder what would be better.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.