Introduction: why does Go complain about your data?
\nImagine: you're writing in Go, everything is going great, but suddenly the compiler gives you an icy message: cannot convert data (type interface {}) to type string: need type assertion. Sound familiar? If you've worked with Go for at least a week, this error has likely visited you. It scares beginners, but in reality, it's a door to the world of type assertion — one of the language's most powerful and simultaneously treacherous mechanisms.
In this article, we won't just break down the error. We'll understand why Go is so strict, how to correctly convert interface{} to a string and other types, and how not to fall into the panic trap. Ready? Let's go.
What is interface{} and why is it tricky?
\nIn Go, interface{} (empty interface) is a type that can hold a value of any type. It sounds like magic, but you have to pay for it: Go does not allow you to simply assign a value from an interface{} variable to a specific type variable. The language requires explicit confirmation: "Hey, I know for sure that there's a string inside, allow me to retrieve it."
This confirmation is called type assertion. Without it, the compiler gives you that exact error:
\nvar data interface{} = "hello"\n// Error:\nstr := data // cannot use data (type interface{}) as type string\n\nWhy? Because data is a black box. The compiler doesn't know what's inside. It could be a string, a number, or even a struct. Safety first.
Type Assertion: savior or source of panic?
\nType assertion is syntax that allows you to "check" and "extract" a value from interface{}. It looks like this:
str := data.(string)\n\nBut there's a catch: if data is not a string, your program will crash with a panic. That's why experienced developers use the checked form (comma ok idiom):
str, ok := data.(string)\nif !ok {\n // Handle the error: this is not a string\n fmt.Println("Error: data is not a string")\n return\n}\nfmt.Println(str)\n\nNow, if data is a number, the program won't crash, it will simply report an error. Always use the checked form if you are not 100% sure of the type.
Real-life example: parsing JSON with interface{}
\nThe most common scenario where our error occurs is working with JSON. When you parse JSON without a strict structure, Go turns everything into map[string]interface{}. And that's where the fun begins.
Let's say we have JSON:
\n{\n "name": "Alice",\n "age": 30\n}\n\nWe parse it:
\njsonStr := `{"name": "Alice", "age": 30}`\nvar result map[string]interface{}\njson.Unmarshal([]byte(jsonStr), &result)\n\n// Trying to get name\nname := result["name"].(string) // Works, but dangerous\nfmt.Println(name) // Alice\n\n// Trying to get age as a string — panic!\nage := result["age"].(string) // panic: interface conversion: interface {} is float64, not string\n\nWhy panic? Because numbers in JSON are parsed as float64 by default, not as a string. Conclusion: never do type assertion without checking.
Correct code:
\nif name, ok := result["name"].(string); ok {\n fmt.Println("Name:", name)\n}\nif age, ok := result["age"].(float64); ok {\n fmt.Println("Age:", int(age))\n}\n\n\nType Switch: when there are many types
\nSometimes you don't know what type is inside interface{}. For such cases, Go offers type switch — a construct that checks all possible variants:
var data interface{} = getSomeData()\n\nswitch v := data.(typ