sprig icon indicating copy to clipboard operation
sprig copied to clipboard

keys function does not work with map[string]struct

Open prune998 opened this issue 4 months ago • 1 comments

I want to get the string keys of a dict which is a map[string]string (or anything different from map[string]interface.

Ex script:

package main

import (
	"html/template"
	"os"

	"github.com/Masterminds/sprig/v3"
)

func main() {
	// Define your data, a map[string]interface{} in this case
	data := map[string]interface{}{
		"MyMap": map[string]string{
			"key1": "value1",
			"key2": "value2",
			"key3": "value3",
		},
	}

	// Create a new template and add Sprig functions
	tmpl, err := template.New("example").Funcs(sprig.FuncMap()).Parse(`
Sprig Keys Example
Keys of MyMap:
  {{ range $key := .MyMap | keys }}
    {{ $key }}
  {{ end }}
	`)
	if err != nil {
		panic(err)
	}

	// Execute the template with the data
	err = tmpl.Execute(os.Stdout, data)
	if err != nil {
		panic(err)
	}
}

This gives an error:

panic: template: example:4:28: executing "example" at <keys>: wrong type for value; expected map[string]interface {}; got map[string]string

I consider that a bug... keys shouldn't care of the values, only the keys... An I missing something ?

prune998 avatar Aug 26 '25 16:08 prune998

I made it work uing the ugliest thing... please let me know if there's a better solution. This example uses map[string]string, but I actually use a map[string]*my-own-struct` so I need to support many types and pointers...

package main

import (
	"encoding/json"
	"html/template"
	"log"
	"os"

	"github.com/Masterminds/sprig/v3" // Import Sprig
)

func main() {
	// Define your data, a map[string]interface{} in this case
	data := map[string]interface{}{
		"MyMap": map[string]string{
			"key1": "value1",
			"key2": "value2",
			"key3": "value3",
		},
	}

	// Create a new template and add Sprig functions
	tmpl, err := template.New("example").Funcs(sprig.FuncMap()).Parse(`
Sprig Keys Example
Keys of MyMap:
  {{- range $key := .MyMap | keys }}
    {{ $key }}
  {{- end -}}
	`)
	if err != nil {
		panic(err)
	}

	// Execute the template with the data

	// Marshall the values inside data
	jsonData, err := json.Marshal(data)
	if err != nil {
		log.Fatal(err)
	}

	// Unmarshall it into a map[string]any
	var result map[string]any
	err = json.Unmarshal(jsonData, &result)
	if err != nil {
		log.Fatal(err)
	}

	// Use the unmarshalled data instead of original data
	data = result
	err = tmpl.Execute(os.Stdout, result)
	if err != nil {
		panic(err)
	}
}

prune998 avatar Aug 26 '25 16:08 prune998