docs: 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