Search code examples
gotypestype-conversiontype-assertion

Type assert custom type to base type


Is it possible to type assert a custom type to its base type?

For example, if I have the following

type A []interface{}

var x = map[string]interface{}{
        "hello":"a",
        "world":A{"b","c"},
    }

y := x["world"]

Then if I try to type assert via y.([]interface{}) I get the error //interface {} is A, not []interface {}.

Edit: As an answer below has noted, I can assert to type A via y.(A). The problem stems from x being given by a Mongo driver. Some drivers implement their own types, for example, the official mongo driver implements a bson.A type for []interface types. If I switch drivers then my type assertions need to change to match their custom types, which is something I want to avoid.


Solution

  • When type asserting (to) a concrete type, you can only type assert the same type that is stored in the interface value, not its base type. Of course when you have the concrete type, you can convert that to its base type.

    You said you want to avoid that, you want to avoid having to refer to the concrete type.

    To do that, you will need reflection. Obtain a reflect.Value descriptor of the value, and use the Value.Convert() method to "directly" convert to its base type, skipping the "actual" type. This will succeed because a value can be converted to a value of its base type.

    Of course the Value.Convert() method will yield a value of type reflect.Value (and not []interface{}), but you can get the interface{} value wrapping this using Value.Interface(). You will now have an interface{} that wraps a concrete value of type []interface{}, from which you can now type assert a value of type []interface{}.

    See this example:

    z := reflect.ValueOf(y).Convert(reflect.TypeOf([]interface{}{})).
        Interface().([]interface{})
    
    fmt.Printf("%T %v", z, z)
    

    Output (try it on the Go Playground):

    []interface {} [b c]
    

    There's a lot of boilerplate here, and this won't be nearly as efficient as a simple type-assertion and conversion. Try to avoid doing it this way.