fix: MapKeys returns empty slice for natively-typed maps

Get() preserves the concrete type of a map[string]T value loaded via
Set() or a provider like structs, but MapKeys() only type-asserted
map[string]any, so it silently reported no keys for anything else.
Read keys via reflection instead so any map with string keys works.
This commit is contained in:
dualfroz committed 2026-09-24 19:15:15 +02:00
1 parent b11959cda7
commit 219bbcd219
2 files changed
+19 -5

No files matched your search

+8 -5
View File
@@ -413,13 +413,16 @@ func (ko *Koanf) MapKeys(path string) []string {
return out
}
mp, ok := o.(map[string]any)
if !ok {
// A value set with Set() or by a Provider such as structs keeps its native
// map type, so the keys have to be read through reflection too.
rv := reflect.ValueOf(o)
if rv.Kind() != reflect.Map || rv.Type().Key().Kind() != reflect.String {
return out
}
out = make([]string, 0, len(mp))
for k := range mp {
out = append(out, k)
out = make([]string, 0, rv.Len())
for _, k := range rv.MapKeys() {
out = append(out, k.String())
}
sort.Strings(out)
return out
+11
View File
@@ -1691,6 +1691,17 @@ func TestTypedGettersNativeMaps(t *testing.T) {
}
}
func TestMapKeysNativeMap(t *testing.T) {
assert := assert.New(t)
k := koanf.New(delim)
assert.NoError(k.Load(confmap.Provider(map[string]any{
"ints": map[string]int64{"a": 1, "b": 2},
}, "."), nil))
assert.Equal([]string{"a", "b"}, k.MapKeys("ints"), "map keys mismatch for a natively-typed map")
}
// waitTimeout waits for the waitgroup for the specified max timeout.
// Returns true if waiting timed out.
func waitTimeout(wg *sync.WaitGroup, timeout time.Duration) bool {