Repository: marpple/FxTS (ts)

Issue:
Add `reverse` function
# Suggestion

<!--
  Please fill in each section completely. Thank you!
-->

## ⭐ Suggestion

<!-- What would you like to be added? -->

Returns the given elements in reverse order.

## 💻 Use Cases

<!-- What do you want to use this for? -->


```ts
reverse([1,2,3,4,5,6]); // [6,5,4,3,2,1]
reverse('abcde'); // 'edcba'
```


Pull request description:
feat: add `reverse` function
Fixes #64 


Patch:
diff --git a/src/index.ts b/src/index.ts
index 2054f2be..5c8a3b30 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -30,6 +30,7 @@ import pickBy from "./pickBy";
 import pipe from "./pipe";
 import pipe1 from "./pipe1";
 import reduce from "./reduce";
+import reverse from "./reverse";
 import some from "./some";
 import sort from "./sort";
 import tap from "./tap";
@@ -70,6 +71,7 @@ export {
   pipe,
   pipe1,
   reduce,
+  reverse,
   some,
   sort,
   tap,
diff --git a/src/reverse.ts b/src/reverse.ts
new file mode 100644
index 00000000..f6e621c2
--- /dev/null
+++ b/src/reverse.ts
@@ -0,0 +1,101 @@
+import toArray from "./toArray";
+import isArray from "./isArray";
+import isString from "./isString";
+import IterableInfer from "./types/IterableInfer";
+import { isAsyncIterable, isIterable } from "./_internal/utils";
+
+type ReturnReverseType<
+  T extends Iterable<unknown> | AsyncIterable<unknown> | string,
+> = T extends string
+  ? string
+  : T extends Iterable<unknown>
+  ? IterableInfer<T>[]
+  : T extends AsyncIterable<unknown>
+  ? Promise<IterableInfer<T>[]>
+  : never;
+
+function stringReverse(str: string) {
+  const arr = Array.from(str);
+  let res = "";
+  for (let i = arr.length - 1; i >= 0; i--) {
+    res += arr[i];
+  }
+  return res;
+}
+
+function sync<T>(iterable: Iterable<T>) {
+  const arr = toArray(iterable);
+  const res = [];
+  for (let i = arr.length - 1; i >= 0; i--) {
+    res.push(arr[i]);
+  }
+  return res;
+}
+
+async function async<T>(iterable: AsyncIterable<T>) {
+  const arr = await toArray(iterable);
+  const res = [];
+  for (let i = arr.length - 1; i >= 0; i--) {
+    res.push(arr[i]);
+  }
+  return res;
+}
+
+/**
+ * Returns the given elements in reverse order.
+ *
+ * @example
+ * ```ts
+ * reverse([1, 2, 3, 4, 5]); // [5, 4, 3, 2, 1]
+ * reverse("abcde"); // "edcba"
+ *
+ * // with pipe
+ * pipe(
+ *  [1, 2, 3, 4, 5],
+ *  reverse,
+ * ); // [5, 4, 3, 2, 1]
+ *
+ * pipe(
+ *  "abcde",
+ *  reverse,
+ * ); // "edcba"
+ *
+ * await pipe(
+ *  [1, 2, 3, 4, 5],
+ *  toAsync,
+ *  reverse,
+ * ); // [5, 4, 3, 2, 1]
+ *
+ * await pipe(
+ *  "abcde",
+ *  toAsync,
+ *  reverse,
+ * ); // ["e", "d", "c", "b", "a"]
+ * ```
+ */
+function reverse<T extends Iterable<unknown> | AsyncIterable<unknown> | string>(
+  iterable: T,
+): ReturnReverseType<T>;
+function reverse<T>(
+  iterable: string | number[] | Iterable<T> | AsyncIterable<T>,
+) {
+  if (isArray(iterable)) {
+    return iterable.reverse();
+  }
+
+  if (isString(iterable)) {
+    return stringReverse(iterable);
+  }
+
+  if (isIterable(iterable)) {
+    return sync(iterable);
+  }
+
+  if (isAsyncIterable(iterable)) {
+    return async(iterable);
+  }
+
+  throw new TypeError("'iterable' must be type of Iterable or AsyncIterable");
+}
+
+export default reverse;
diff --git a/src/sort.ts b/src/sort.ts
index d4a51a21..10adee79 100644
--- a/src/sort.ts
+++ b/src/sort.ts
@@ -18,7 +18,7 @@ import toArray from "./toArray";
 function sort(
     f: (a: any, b: any) => unknown,
     iterable: readonly []
-  ): any[];
+): any[];
 
 // prettier-ignore
 function sort<T>(


Test patch:
diff --git a/test/reverse.spec.ts b/test/reverse.spec.ts
new file mode 100644
index 00000000..6524dda2
--- /dev/null
+++ b/test/reverse.spec.ts
@@ -0,0 +1,43 @@
+import { pipe, toAsync, reverse } from "../src";
+
+describe("reverse", function () {
+  describe("sync", function () {
+    it.each([
+      [
+        [1, 2, 3, 4],
+        [4, 3, 2, 1],
+      ],
+      ["abcd", "dcba"],
+    ])(
+      "should return the given elements %s in reverse order %s",
+      function (input, result) {
+        expect(reverse(input)).toEqual(result);
+      },
+    );
+
+    it("should be able to be used as a curried function in the pipeline", function () {
+      const res = pipe([1, 2, 3, 4], reverse);
+      expect(res).toEqual([4, 3, 2, 1]);
+    });
+  });
+
+  describe("async", function () {
+    it.each([
+      [
+        [1, 2, 3, 4],
+        [4, 3, 2, 1],
+      ],
+      ["abcd", ["d", "c", "b", "a"]],
+    ])(
+      "should return the given elements %s in reverse order %s",
+      async function (input, result) {
+        expect(await reverse(toAsync(input as any))).toEqual(result);
+      },
+    );
+
+    it("should be able to be used as a curried function in the pipeline", async function () {
+      const res = await pipe([1, 2, 3, 4], toAsync, reverse);
+      expect(res).toEqual([4, 3, 2, 1]);
+    });
+  });
+});
diff --git a/type-check/reverse.test.ts b/type-check/reverse.test.ts
new file mode 100644
index 00000000..780cb98e
--- /dev/null
+++ b/type-check/reverse.test.ts
@@ -0,0 +1,24 @@
+import * as Test from "../src/types/Test";
+import { reverse, pipe, toAsync } from "../src";
+
+const { checks, check } = Test;
+
+const res1 = reverse([]);
+const res2 = reverse([1, 2, 3, 4]);
+const res3 = reverse("abcd");
+const res4 = reverse(toAsync([1, 2, 3, 4]));
+const res5 = reverse(toAsync("abcd"));
+const res6 = pipe([], reverse);
+const res7 = pipe(toAsync([1, 2, 3, 4]), reverse);
+const res8 = pipe(toAsync("abcd"), reverse);
+
+checks([
+  check<typeof res1, never[], Test.Pass>(),
+  check<typeof res2, number[], Test.Pass>(),
+  check<typeof res3, string, Test.Pass>(),
+  check<typeof res4, Promise<number[]>, Test.Pass>(),
+  check<typeof res5, Promise<string[]>, Test.Pass>(),
+  check<typeof res6, never[], Test.Pass>(),
+  check<typeof res7, Promise<number[]>, Test.Pass>(),
+  check<typeof res8, Promise<string[]>, Test.Pass>(),
+]);