dbrattli/Expression

How about using TypeAlias with Result and Option?

Closed this issue · 1 comments

Is your feature request related to a problem? Please describe.
I often use method "is_ok" and "is_error", but unfortunately, pylance does not recognize it

import typing as tp

import expression as ex


def get_result() -> ex.Result[int, tp.Any]:
    return ex.Ok(1)


a = get_result()
if a.is_ok():
    b = a  # in pylance:: (variable) b: Result[int, Any]
    # in pylance:: Cannot access member "value" for type "Result[int, Any]"
    #   Member "value" is unknown
    v = a.value
else:
    b = a  # in pylance:: (variable) b: Result[int, Any]
    # in pylance:: Cannot access member "error" for type "Result[int, Any]"
    #   Member "error" is unknown
    v = a.error

So I'm replacing it with "isinstance", but it's still a little disappointing

import typing as tp

import expression as ex


def get_result() -> ex.Result[int, tp.Any]:
    return ex.Ok(1)


a = get_result()
if isinstance(a, ex.Ok):
    b = a  # in pylance:: (variable) b: Ok[int, Any]
    v = a.value  # in pylance:: (variable) v: int
else:
    b = a  # in pylance:: (variable) b: Result[int, Any]
    # in pylance:: Cannot access member "error" for type "Result[int, Any]"
    #   Member "error" is unknown
    v = a.error

c = get_result()
if isinstance(c, ex.Error):
    d = c  # in pylance:: (variable) d: Error[int, Any]
    v = c.error  # in pylance:: (variable) v: Any
else:
    d = c  # in pylance:: (variable) d: Result[int, Any]
    # in pylance:: Cannot access member "value" for type "Result[int, Any]"
    #   Member "value" is unknown
    v = c.value

Describe the solution you'd like

It looks better when using TypeAlias

import typing as tp

import expression as ex
import typing_extensions as tpe

TValue = tp.TypeVar("TValue")
TError = tp.TypeVar("TError")

TypedResult: tpe.TypeAlias = tp.Union[ex.Ok[TValue, TError], ex.Error[TValue, TError]]


def get_typed_result() -> TypedResult[int, tp.Any]:
    return ex.Ok(1)


a2 = get_typed_result()
if isinstance(a2, ex.Ok):
    b2 = a2  # in pylance:: (variable) b2: Ok[int, Any]
    v2 = a2.value  # in pylance:: (variable) v2: int
else:
    b2 = a2  # in pylance:: (variable) b2: Error[int, Any]
    v2 = a2.error  # in pylance:: (variable) v2: Any

c2 = get_typed_result()
if isinstance(c2, ex.Error):
    d2 = c2  # in pylance:: (variable) d2: Error[int, Any]
    v2 = c2.error  # in pylance:: (variable) v2: Any
else:
    d2 = c2  # in pylance:: (variable) d2: Ok[int, Any]
    v2 = c2.value  # in pylance:: (variable) v2: int

If Result and Option were used simply to define the interface, I think its could be easily replaced. But I'm not sure, so I can't pr and just suggest it.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

Additional context
Python 3.10.9
vscode 1.74.3
pylance 2023.1.40