A comprehensive, high-performance toolkit for slice manipulation in Go, inspired by JavaScript's Array.prototype methods but architected for bare-metal Go performance.
- ✅ Familiar API —
Filter,Map,Reduce,Push,Pop,Includes, and 30+ more, named to match their JS counterparts. - ✅ Zero-Allocation Fast Paths — Core operations on primitives (like
JoinorReduceAs) are optimized to bypass interface boxing, running at sub-nanosecond speeds with zero heap allocations. - ✅ Go 1.23 Iterators — Native support for lazy iteration (
iter.Seq,iter.Seq2), allowing massive datasets to be processed with exactly0 B/opoverhead. - ✅ 100% Test Coverage — Fully verified, edge-case hardened, and production-ready.
- ✅ Two styles — use plain functions (
array.Filter(slice, fn)) or the fluentArray[T]type with chainable methods. - ✅ Immutable by default — every operation returns a new slice; the original is never mutated.
- ✅ Negative indexes —
At,Slice,IndexOf, etc. accept negative indexes and return clear errors instead of panicking. - ✅ Type-safe generics — including a fully generic
Map[T, V]that returns[]V, not[]any.
Requires Go 1.23+ to support native iterators.
go get github.com/bube054/go-js-array-methods/v2@v2.1.0v2.1.0 update: Added Go 1.23
iter.Seqsupport (Keys,Values,EntriesIterator) and zero-allocationReduceAspipelines. See CHANGELOG.md for details.
package main
import (
"fmt"
"github.com/bube054/go-js-array-methods/v2/array"
)
func main() {
nums := []int{1, 2, 3, 4, 5}
even := array.Filter(nums, func(n, _ int, _ []int) bool { return n%2 == 0 })
doubled := array.Map(even, func(n, _ int, _ []int) int { return n * 2 })
fmt.Println(doubled) // [4 8]
}package main
import (
"fmt"
"github.com/bube054/go-js-array-methods/v2/array"
)
func main() {
arr := array.Array[int]{1, 2, 3, 4, 5}
result := arr.
Filter(func(n, _ int, _ []int) bool { return n%2 == 0 }).
Push(6).
Reverse()
fmt.Println(result) // [6 4 2]
}Both styles are interchangeable — pick the one that fits your code.
| # | Method | Status | Summary |
|---|---|---|---|
| 1 | At |
✔ | Index into a slice (supports negative indexes). |
| 2 | Concat |
✔ | Join two or more slices into a new slice. |
| 3 | CopyWithin |
✔ | Copy a section of a slice to another position within the same slice. |
| 4 | Entries |
✔ | Return []Entry{Index, Value}. |
| 5 | EntriesIterator |
✔ | Go 1.23 Iterator: Yields (index, value) pairs as iter.Seq2. |
| 6 | Every |
✔ | true if every element passes the predicate. |
| 7 | Fill |
✔ | Fill a range with a static value. |
| 8 | Filter |
✔ | Keep elements that pass the predicate. |
| 9 | Find |
✔ | Pointer to the first matching element, or nil. |
| 10 | FindIndex |
✔ | Index of the first match, or -1. |
| 11 | FindLast |
✔ | Pointer to the last matching element, or nil. |
| 12 | FindLastIndex |
✔ | Index of the last match, or -1. |
| 13 | Flat |
✔ | Flatten nested []any to a typed []T (configurable depth). |
| 14 | FlatMap |
❌ | Not implemented. |
| 15 | ForEach |
✔ | Run a callback for each element. |
| 16 | Includes |
✔ | true if the slice contains the value. |
| 17 | IndexOf |
✔ | First index of a value, or -1. |
| 18 | Join |
✔ | Stringify and join elements with a separator (0 allocs for primitives). |
| 19 | Keys |
✔ | Go 1.23 Iterator: Yields indexes as iter.Seq[int]. |
| 20 | LastIndexOf |
✔ | Last index of a value, or -1. |
| 21 | Map |
✔ | Transform each element. Returns []V (generic over output type). |
| 22 | MapStrict |
✔ | Transform each element to the same type T. |
| 23 | Pop |
✔ | Return slice without last element + pointer to popped value. |
| 24 | Push |
✔ | Append elements; returns new slice. |
| 25 | Reduce |
✔ | Fold to a single value of any type (JS-fidelity dynamic accumulator). |
| 26 | ReduceAs |
✔ | 0-Alloc Fast Path: Reduce to a specific type without interface boxing. Empty input with no initial value panics with a TypeError |
| 27 | ReduceStrict |
✔ | Fold to a single value of the same type as the elements. |
| 28 | ReduceRight |
✔ | Fold from right to left. |
| 29 | ReduceRightAs |
✔ | 0-Alloc Fast Path: Right-fold to a specific type without boxing. Empty input with no initial value panics with a TypeError |
| 30 | ReduceRightStrict |
✔ | Right-to-left fold with strict typing. |
| 31 | Reverse |
✔ | Reverse a slice; returns new slice. |
| 32 | Shift |
✔ | Return slice without first element + pointer to shifted value. |
| 33 | Slice |
✔ | Sub-slice from start to end (exclusive), supports negative indexes. |
| 34 | Some |
✔ | true if any element passes the predicate. |
| 35 | Sort |
❌ | Use the standard library's sort / slices packages. |
| 36 | Splice |
✔ | Remove and/or insert elements at an index. |
| 37 | ToString |
✔ | Comma-separated string representation. |
| 38 | UnShift |
✔ | Prepend elements; returns new slice. |
| 39 | ValueOf |
✔ | Identity — returns the slice itself. |
| 40 | Values |
✔ | Go 1.23 Iterator: Yields values as iter.Seq[T]. |
| 41 | With |
✔ | Return a copy with the element at index replaced. |
For full signatures, runnable examples, and per-method docs, see pkg.go.dev.
- Zero-Allocation Fast Paths: When type safety is explicitly defined, this library compiles down to bare-metal loops. Operations like
ReduceAsand primitiveJoinbypass Go's escape analysis interface boxing entirely, achieving0 allocs/op. - Dynamic JS-Fidelity vs. Static Speed: Methods like standard
Reduceare designed for complete JavaScript parity (allowing an accumulator to dynamically change types), which incurs a runtime boxing tax. For highly optimized, zero-allocation pipelines, useReduceAsorReduceStrict. - Lazy Iterators (Go 1.23): Using
.EntriesIterator(),.Keys(), or.Values()returns native Go iterators. Processing a massive array eagerly allocates memory proportionally, while lazy iterators process the same data with exactly0 Bytesof heap overhead. - Immutability: Every function returns a new slice. The original input is never modified.
- Negative Indexes: Methods gracefully accept negative indexes (
At(-1)gets the last element) and return typed errors instead of panicking on out-of-bounds access.
A few common patterns. See array/example_test.go
for many more (also rendered on pkg.go.dev).
Memory-Free Lazy Iteration (Go 1.23+) Process large datasets without intermediate slice allocations using native iterators:
arr := array.Array[string]{"alice", "bob", "carol"}
for index, value := range arr.EntriesIterator() {
fmt.Printf("Index: %d, Value: %s\n", index, value)
}Zero-Allocation Type Reduction (ReduceAs)
Safely transform a slice of integers into a completely different type (e.g., a string) without heap allocations:
nums := []int{1, 2, 3}
str, _ := array.ReduceAs(nums, func(acc string, curr, _ int, _ []int) string {
return acc + strconv.Itoa(curr)
}, "")
// str == "123"Sum a slice with ReduceStrict:
nums := []int{1, 2, 3, 4}
initial := 0
sum, _ := array.ReduceStrict(nums, func(acc, n, _ int, _ []int) int {
return acc + n
}, &initial)
// sum == 10Flatten a mixed nested slice:
nested := []any{1, []int{2, 3}, []int{4, 5}}
flat, _ := array.Flat[int](nested)
// flat == []int{1, 2, 3, 4, 5}Chain transforms with Array[T]:
arr := array.Array[string]{"alice", "bob", "carol"}
shouts := arr.MapStrict(func(s string, _ int, _ []string) string {
return strings.ToUpper(s) + "!"
})
// shouts == [ALICE! BOB! CAROL!]A representative benchmark suite proving our zero-allocation guarantees lives in
array/benchmark_test.go. Run it with:
go test -bench=. -benchmem ./array/Issues and PRs welcome! See CONTRIBUTING.md for the dev loop, coding conventions, and what we look for in a PR.
See CHANGELOG.md.