From 41cbf0fd2b8ee2965bf4315fe3178cf73875535e Mon Sep 17 00:00:00 2001 From: Nathan Baulch Date: Thu, 25 Sep 2025 06:57:40 +1000 Subject: [PATCH] feat: preserve type alias in DropByIndex and WithoutBy (#675) * lint: pin golangci-lint version * feat: preserve type alias in WithoutBy * feat: preserve type alias in DropByIndex --------- Co-authored-by: Samuel Berthe --- .github/workflows/lint.yml | 1 + intersect.go | 4 ++-- intersect_test.go | 9 ++++++++- slice.go | 6 +++--- slice_test.go | 5 +++++ 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index cb39e01..934666a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -17,6 +17,7 @@ jobs: - name: golangci-lint uses: golangci/golangci-lint-action@v8 with: + version: 'v2.4' args: --timeout 120s --max-same-issues 50 - name: Bearer diff --git a/intersect.go b/intersect.go index 8c64758..ad0a086 100644 --- a/intersect.go +++ b/intersect.go @@ -196,13 +196,13 @@ func Without[T comparable, Slice ~[]T](collection Slice, exclude ...T) Slice { // WithoutBy filters a slice by excluding elements whose extracted keys match any in the exclude list. // Returns a new slice containing only the elements whose keys are not in the exclude list. // Play: https://go.dev/play/p/VgWJOF01NbJ -func WithoutBy[T any, K comparable](collection []T, iteratee func(item T) K, exclude ...K) []T { +func WithoutBy[T any, K comparable, Slice ~[]T](collection Slice, iteratee func(item T) K, exclude ...K) Slice { excludeMap := make(map[K]struct{}, len(exclude)) for _, e := range exclude { excludeMap[e] = struct{}{} } - result := make([]T, 0, len(collection)) + result := make(Slice, 0, len(collection)) for _, item := range collection { if _, ok := excludeMap[iteratee(item)]; !ok { result = append(result, item) diff --git a/intersect_test.go b/intersect_test.go index fdf39eb..3234320 100644 --- a/intersect_test.go +++ b/intersect_test.go @@ -288,8 +288,15 @@ func TestWithoutBy(t *testing.T) { result2 := WithoutBy([]User{}, func(item User) int { return item.Age }, 1, 2, 3) result3 := WithoutBy([]User{}, func(item User) string { return item.Name }) is.Equal([]User{{Name: "peter"}}, result1) - is.Empty(result2) + is.Empty(result2) is.Empty(result3) + + type myStrings []string + allStrings := myStrings{"", "foo", "bar"} + nonempty := WithoutBy(allStrings, func(s string) string { + return s + }) + is.IsType(nonempty, allStrings, "type preserved") } func TestWithoutEmpty(t *testing.T) { diff --git a/slice.go b/slice.go index 21d60aa..39dc39c 100644 --- a/slice.go +++ b/slice.go @@ -490,10 +490,10 @@ func DropRightWhile[T any, Slice ~[]T](collection Slice, predicate func(item T) // DropByIndex drops elements from a slice by the index. // A negative index will drop elements from the end of the slice. // Play: https://go.dev/play/p/bPIH4npZRxS -func DropByIndex[T any](collection []T, indexes ...int) []T { +func DropByIndex[T any, Slice ~[]T](collection Slice, indexes ...int) Slice { initialSize := len(collection) if initialSize == 0 { - return make([]T, 0) + return make(Slice, 0) } for i := range indexes { @@ -505,7 +505,7 @@ func DropByIndex[T any](collection []T, indexes ...int) []T { indexes = Uniq(indexes) sort.Ints(indexes) - result := make([]T, 0, initialSize) + result := make(Slice, 0, initialSize) result = append(result, collection...) for i := range indexes { diff --git a/slice_test.go b/slice_test.go index bb72278..85e7053 100644 --- a/slice_test.go +++ b/slice_test.go @@ -716,6 +716,11 @@ func TestDropByIndex(t *testing.T) { is.Empty(DropByIndex([]int{42}, 1, 0)) is.Empty(DropByIndex([]int{}, 1)) is.Empty(DropByIndex([]int{1}, 0)) + + type myStrings []string + allStrings := myStrings{"", "foo", "bar"} + nonempty := DropByIndex(allStrings, 0) + is.IsType(nonempty, allStrings, "type preserved") } func TestReject(t *testing.T) {