Hi all,

I've been reading about the TypeGuards coming in 3.10 (and I'm excited!). I have a question which is related to guards and casts.

One use-case I have is parsing data from some external source (e.g. JSON from a web API), but then presenting the result as a well-typed-value. For example:

def get_error_code(error_data: Dict[str, Any]) -> str:
    code = error_data["code"]
    if isinstance(code, str):
        return code
    raise ValueError("bah! bad code!")

The type of a value from an untrustworthy source should be checked at runtime, and we raise an error if the type is not correct.

There are a few other ways of writing this, but with pitfalls of varying levels of obviousness. e.g.

return cast(str, error_data["code"])

or

code = error_data["code"]
assert isinstance(code, str)
return code

The cast has no runtime check, and any `assert` gets removed if optimization is used. The `cast` "says what I mean" most succinctly, but by design doesn't include a runtime check.

This seems like something which could be made the responsibility of `typing` in 3.11 or later. For example, an 'asserting_cast' variant which takes a (TypeGuard | Type) and lets the above examples be written as

code = error_data["code"]
return asserting_cast(code, str)

or, to clarify the TypeGuard case,

def is_str(x: Any) -> TypeGuard[str]:
    return isinstance(x, str)
...
code = error_data["code"]
return asserting_cast(code, is_str)


I think the implementation would be quite simple, but IMO there's value in stdlib `typing` providing a pre-built solution which has thought about odd cases like non-runtime-checkable protocols.

I'd be more than happy to work on adding something like this to `typing` if it seems reasonable. It would be a "safer but slower" alternative to cast and can raise a custom error, e.g. FailedTypeCastError(ValueError) .


My biggest two questions are...
Have I missed something obvious in `typing` or maybe `typing-extensions` which already covers this?
Is this a bad idea, and if so can someone help me understand why?


Thanks in advance,
-Stephen