Skip to content

Commit 0830d8b

Browse files
committed
Add popArray for mutating non-empty arrays
1 parent 9509d18 commit 0830d8b

3 files changed

Lines changed: 60 additions & 1 deletion

File tree

.changeset/afraid-wolves-lay.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@evolu/common": minor
3+
---
4+
5+
Add `popArray` function for removing and returning the last element from a non-empty mutable array.
6+
7+
This complements the existing `shiftArray` function by providing symmetric mutable operations for both ends of arrays. The function ensures type safety by only accepting mutable non-empty arrays and guaranteeing a return value.

packages/common/src/Array.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Array types, type guards, operations, transformations, accessors, and
2+
* Array types, type guards, operations, transformations, accessors, and (rare)
33
* mutations
44
*
55
* ### Example
@@ -414,3 +414,20 @@ export const lastInArray = <T>(array: NonEmptyReadonlyArray<T>): T =>
414414
* @category Mutations
415415
*/
416416
export const shiftArray = <T>(array: NonEmptyArray<T>): T => array.shift() as T;
417+
418+
/**
419+
* Pops an item from a non-empty mutable array, guaranteed to return T.
420+
*
421+
* **Mutates** the original array.
422+
*
423+
* ### Example
424+
*
425+
* ```ts
426+
* const arr: NonEmptyArray<number> = [1, 2, 3];
427+
* popArray(arr); // 3
428+
* arr; // [1, 2]
429+
* ```
430+
*
431+
* @category Mutations
432+
*/
433+
export const popArray = <T>(array: NonEmptyArray<T>): T => array.pop() as T;

packages/common/test/Array.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
lastInArray,
1010
mapArray,
1111
partitionArray,
12+
popArray,
1213
prependToArray,
1314
shiftArray,
1415
type NonEmptyArray,
@@ -398,4 +399,38 @@ describe("Mutations", () => {
398399
shiftArray([1, 2, 3] as NonEmptyReadonlyArray<number>);
399400
});
400401
});
402+
403+
describe("popArray", () => {
404+
test("pops last element from array", () => {
405+
const arr: NonEmptyArray<number> = [1, 2, 3];
406+
const result = popArray(arr);
407+
expect(result).toBe(3);
408+
expect(arr).toEqual([1, 2]);
409+
});
410+
411+
test("pops from single element array", () => {
412+
const arr: NonEmptyArray<number> = [42];
413+
const result = popArray(arr);
414+
expect(result).toBe(42);
415+
expect(arr).toEqual([]);
416+
});
417+
418+
test("mutates the original array", () => {
419+
const arr: NonEmptyArray<string> = ["a", "b", "c"];
420+
popArray(arr);
421+
expect(arr).toEqual(["a", "b"]);
422+
});
423+
424+
test("only accepts mutable arrays", () => {
425+
const mutableArr: NonEmptyArray<number> = [1, 2, 3];
426+
const result = popArray(mutableArr);
427+
expect(result).toBe(3);
428+
expect(mutableArr).toEqual([1, 2]);
429+
expectTypeOf(result).toEqualTypeOf<number>();
430+
431+
// Verify readonly arrays are NOT accepted by TypeScript
432+
// @ts-expect-error - readonly arrays cannot be mutated
433+
popArray([1, 2, 3] as NonEmptyReadonlyArray<number>);
434+
});
435+
});
401436
});

0 commit comments

Comments
 (0)