def typecast(type_, value):
<EOL>if is_builtin_type(type_) or is_collections_type(type_) or is_enum_type(type_):<EOL><INDENT>if is_bytes_type(type_):<EOL><INDENT>return decode_bytes(value)<EOL><DEDENT>return type_(value)<EOL><DEDENT>elif is_regex_type(type_):<EOL><INDENT>return typecast(str, value)<EOL><DEDENT>elif is_typing_type(type_):<EOL><INDENT>try:<EOL><INDENT>base_type = type_.__extra__<EOL><DEDENT>except AttributeError:<EOL><INDENT>base_type = type_.__origin__<EOL><DEDENT>arg_types = type_.__args__<EOL>if is_array_type(type_):<EOL><INDENT>if len(arg_types) == <NUM_LIT:1>:<EOL><INDENT>item_type = arg_types[<NUM_LIT:0>]<EOL>return base_type([typecast(item_type, item) for item in value])<EOL><DEDENT>else:<EOL><INDENT>return base_type(value)<EOL><DEDENT><DEDENT>elif is_object_type(type_):<EOL><INDENT>if len(arg_types) == <NUM_LIT:2>:<EOL><INDENT>(key_type, item_type) = arg_types<EOL>return base_type(<EOL>{<EOL>typecast(key_type, key): typecast(item_type, item)<EOL>for (key, item) in value.items()<EOL>}<EOL>)<EOL><DEDENT>else:<EOL><INDENT>return base_type(value)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>return base_type(value)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>return value<EOL><DEDENT>
Tries to smartly typecast the given value with the given type.

    :param type_: The type to try to use for the given value
    :param value: The value to try and typecast to the given type
    :return: The typecasted value if possible, otherwise just the original value