<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def typecast(type_, value):
 """ 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 """


    # NOTE: does not do any special validation of types before casting
    # will just raise errors on type casting failures
    if is_builtin_type(type_) or is_collections_type(type_) or is_enum_type(type_):
        # FIXME: move to Types enum and TYPE_MAPPING entry
        if is_bytes_type(type_):
            return decode_bytes(value)
        return type_(value)
    elif is_regex_type(type_):
        return typecast(str, value)
    elif is_typing_type(type_):
        try:
            base_type = type_.__extra__
        except AttributeError:
            # NOTE: when handling typing._GenericAlias __extra__ is actually __origin__
            base_type = type_.__origin__
        arg_types = type_.__args__

        if is_array_type(type_):
            if len(arg_types) == 1:
                item_type = arg_types[0]
                return base_type([typecast(item_type, item) for item in value])
            else:
                return base_type(value)
        elif is_object_type(type_):
            if len(arg_types) == 2:
                (key_type, item_type) = arg_types
                return base_type(
                    {
                        typecast(key_type, key): typecast(item_type, item)
                        for (key, item) in value.items()
                    }
                )
            else:
                return base_type(value)
        else:
            return base_type(value)
    else:
        return value