How can I check the type of a NewType value?

698 Views Asked by At

How do you check the value of NewType against its basic type str without casting and mixing up type checking?

I declared a new type:

BoardId = NewType("BoardId", str)

that I use as a method parameter either as a single value or as an Iteration other than str.

I use instanceof to check if the type is str and not Tuple then I convert it to a tuple otherwise use it as it is. The problem pyright things BoardId is str because of isinstance which fails the type checking. On the other hand, I cannot use isinstance against NewType since:

TypeError: isinstance() arg 2 must be a type, a tuple of types, or a union

Leaving as it is

    async def get_stickies(
        self, board_id: Union[BoardId, Iterable[BoardId]]
    ) -> List[Sticky]:
        board_ids: Iterable[BoardId] = (
            (board_id,) if isinstance(board_id, str) else board_id
        )

causes this issue:

Diagnostics:                                                                                                                      
1. Expression of type "tuple[BoardId | str] | Iterable[BoardId]" cannot be assigned to declared type "Iterable[BoardId]"
     Type "tuple[BoardId | str] | Iterable[BoardId]" cannot be assigned to type "Iterable[BoardId]"
       TypeVar "_T_co@Iterable" is covariant
         Type "BoardId | str" cannot be assigned to type "BoardId"
           "str" is incompatible with "BoardId"

enter image description here

1

There are 1 best solutions below

0
STerliakov On

One solution was proposed in this issue:

from typing import Iterable, TypeAlias, NewType

_BoardIdT: TypeAlias = str
BoardId = NewType('BoardId', _BoardIdT)

def get_stickies(board_id: BoardId | Iterable[BoardId]) -> None:
    board_ids: Iterable[BoardId] = (
        (board_id,) if isinstance(board_id, _BoardIdT) else board_id
    )

Playground link

The underlying type is accessible via BoardId.__supertype__, but mypy doesn't like this undocumented attribute.