Repository: marpple/FxTS (ts)

Issue:
FxTS v0.3 plan
## New Functions
### Lazy
- [x] [pick & omit](https://github.com/marpple/fxts/issues/21)
- [x] [pickBy & omitBy](https://github.com/marpple/fxts/issues/45)
- [x] [pluck](https://github.com/marpple/FxTS/issues/28)
- [x] [dropWhile & dropUntil](https://github.com/marpple/FxTS/issues/22)
- [x] [zipWith](https://github.com/marpple/FxTS/issues/31)
- [x] [split](https://github.com/marpple/FxTS/issues/26)

### Strict
- [x] [join](https://github.com/marpple/fxts/issues/8)
- [x] [includes (alias as `contains`)](https://github.com/marpple/FxTS/issues/46)
- [x] [findIndex](https://github.com/marpple/fxts/issues/41)
- [x] [nth](https://github.com/marpple/FxTS/issues/47)
- [x] [sort](https://github.com/marpple/FxTS/issues/52)
- [x] [isObject](https://github.com/marpple/FxTS/issues/51)
- [x] [isNil](https://github.com/marpple/FxTS/issues/43)

### Function Composition
- [x] [curry](https://github.com/marpple/FxTS/issues/12)
Add `pick` and `omit` function
# Suggestion

<!--
  Please fill in each section completely. Thank you!
-->

## ⭐ Suggestion

<!-- What would you like to be added? -->

## 💻 Use Cases

```ts

const product = {
  name: 'iphone',
  price: 1000,
  description: '...',
  image_url: '...',
};

pick(["name", "price"], product); // { name: 'iphone', price: 1000 }

omit(["name", "price"], product); // { description: '...', image_url: '...' }

```

<!-- What do you want to use this for? -->


Pull request description:
Feature/20
Fixes #21 


Patch:
diff --git a/src/Lazy/dropUntil.ts b/src/Lazy/dropUntil.ts
new file mode 100644
index 00000000..5c12d08e
--- /dev/null
+++ b/src/Lazy/dropUntil.ts
@@ -0,0 +1,150 @@
+import IterableInfer from "../types/IterableInfer";
+import ReturnIterableIteratorType from "../types/ReturnIterableIteratorType";
+import { AsyncFunctionException } from "../_internal/error";
+import { isAsyncIterable, isIterable } from "../_internal/utils";
+import concurrent, { isConcurrent } from "./concurrent";
+
+function* sync<A, B>(f: (a: A) => B, iterable: Iterable<A>) {
+  const iterator = iterable[Symbol.iterator]();
+  const iterableIterator = {
+    [Symbol.iterator]() {
+      return iterator;
+    },
+  };
+
+  for (const a of iterableIterator) {
+    const res = f(a);
+    if (res instanceof Promise) {
+      throw new AsyncFunctionException();
+    }
+
+    if (res) {
+      yield* iterableIterator;
+    }
+  }
+}
+
+async function* asyncSequential<A, B>(
+  f: (a: A) => B,
+  iterable: AsyncIterable<A>,
+) {
+  const iterator = iterable[Symbol.asyncIterator]();
+  const iterableIterator = {
+    [Symbol.asyncIterator]() {
+      return iterator;
+    },
+  };
+
+  for await (const a of iterableIterator) {
+    if (await f(a)) {
+      yield* iterableIterator;
+    }
+  }
+}
+
+function async<A, B>(
+  f: (a: A) => B,
+  iterable: AsyncIterable<A>,
+): AsyncIterableIterator<A> {
+  let iterator: AsyncIterator<A>;
+  return {
+    [Symbol.asyncIterator]() {
+      return this;
+    },
+
+    async next(_concurrent: any) {
+      if (iterator === undefined) {
+        iterator = isConcurrent(_concurrent)
+          ? asyncSequential(f, concurrent(_concurrent.length, iterable))
+          : asyncSequential(f, iterable);
+      }
+
+      return iterator.next(_concurrent);
+    },
+  };
+}
+
+/**
+ * Returns Iterable/AsyncIterable excluding elements dropped from the beginning.
+ * Elements are deleted until the value applied to f returns truly. (It is deleted including the first value applied as true)
+ *
+ * @example
+ * ```ts
+ * const iter = dropUntil((a) => a < 3, [1, 2, 3, 4, 5, 1, 2]);
+ * iter.next(); // {done:false, value: 3}
+ * iter.next(); // {done:false, value: 4}
+ * iter.next(); // {done:false, value: 5}
+ *
+ * // with pipe
+ * pipe(
+ *  [1, 2, 3, 4, 5, 1, 2],
+ *  dropUntil((a) => a > 3),
+ *  toArray,
+ * ); // [5, 1, 2]
+ *
+ * await pipe(
+ *  Promise.resolve([1, 2, 3, 4, 5, 1, 2]),
+ *  dropUntil((a) => a > 3),
+ *  toArray,
+ * ); // [5, 1, 2]
+ *
+ * // if you want to use asynchronous callback
+ * await pipe(
+ *  Promise.resolve([1, 2, 3, 4, 5, 1, 2]),
+ *  toAsync,
+ *  dropUntil(async (a) => a > 3),
+ *  toArray,
+ * ); // [5, 1, 2]
+ *
+ * // with toAsync
+ * await pipe(
+ *  [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3), Promise.resolve(4),
+ * Promise.resolve(5), Promise.resolve(1), Promise.resolve(2)],
+ *  toAsync,
+ *  dropUntil((a) => a > 3),
+ *  toArray,
+ * ); // [5, 1, 2]
+ *
+ * see {@link https://fxts.dev/docs/pipe | pipe}, {@link https://fxts.dev/docs/toAsync | toAsync},
+ * {@link https://fxts.dev/docs/toArray | toArray}
+ * ```
+ */
+function dropUntil<A, B = unknown>(
+  f: (a: A) => B,
+  iterable: Iterable<A>,
+): IterableIterator<A>;
+
+function dropUntil<A, B = unknown>(
+  f: (a: A) => B,
+  iterable: AsyncIterable<A>,
+): AsyncIterableIterator<A>;
+
+function dropUntil<A extends Iterable<unknown> | AsyncIterable<unknown>, B>(
+  f: (a: IterableInfer<A>) => B,
+): (iterable: A) => ReturnIterableIteratorType<A>;
+
+function dropUntil<A extends Iterable<unknown> | AsyncIterable<unknown>, B>(
+  f: (a: IterableInfer<A>) => B,
+  iterable?: A,
+):
+  | IterableIterator<IterableInfer<A>>
+  | AsyncIterableIterator<IterableInfer<A>>
+  | ((iterable: A) => ReturnIterableIteratorType<A>) {
+  if (iterable === undefined) {
+    return (iterable: A) => {
+      return dropUntil(f, iterable as any) as ReturnIterableIteratorType<A>;
+    };
+  }
+
+  if (isIterable(iterable)) {
+    return sync(f, iterable as Iterable<IterableInfer<A>>);
+  }
+
+  if (isAsyncIterable(iterable)) {
+    return async(f, iterable as AsyncIterable<IterableInfer<A>>);
+  }
+
+  throw new TypeError("iterable must be type of Iterable or AsyncIterable");
+}
+
+export default dropUntil;
diff --git a/src/Lazy/index.ts b/src/Lazy/index.ts
index fbbaf842..2bc3fff9 100644
--- a/src/Lazy/index.ts
+++ b/src/Lazy/index.ts
@@ -5,6 +5,7 @@ import concat from "./concat";
 import concurrent from "./concurrent";
 import drop from "./drop";
 import dropWhile from "./dropWhile";
+import dropUntil from "./dropUntil";
 import filter from "./filter";
 import flat from "./flat";
 import flatMap from "./flatMap";
@@ -31,6 +32,7 @@ export {
   concurrent,
   drop,
   dropWhile,
+  dropUntil,
   filter,
   flat,
   flatMap,
diff --git a/src/index.ts b/src/index.ts
index 07424ef7..f0f62157 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -12,7 +12,9 @@ import isString from "./isString";
 import join from "./join";
 import last from "./last";
 import not from "./not";
+import omit from "./omit";
 import partition from "./partition";
+import pick from "./pick";
 import pipe from "./pipe";
 import pipe1 from "./pipe1";
 import reduce from "./reduce";
@@ -36,7 +38,9 @@ export {
   join,
   last,
   not,
+  omit,
   partition,
+  pick,
   pipe,
   pipe1,
   reduce,
diff --git a/src/omit.ts b/src/omit.ts
new file mode 100644
index 00000000..d28163c2
--- /dev/null
+++ b/src/omit.ts
@@ -0,0 +1,102 @@
+import IterableInfer from "./types/IterableInfer";
+import { isAsyncIterable, isIterable } from "./_internal/utils";
+import toArray from "./toArray";
+
+function inner<T>(obj: T, keys: Set<keyof T>) {
+  return Object.fromEntries(
+    Object.entries(obj).filter(([k]) => !keys.has(k as keyof T)),
+  );
+}
+
+function sync<T extends object, U extends Iterable<keyof T>>(
+  iterable: U,
+  obj: T,
+): Omit<T, IterableInfer<U>> {
+  const keys = new Set(iterable);
+  return inner(obj, keys) as Omit<T, IterableInfer<U>>;
+}
+
+async function async<T extends object, U extends AsyncIterable<keyof T>>(
+  iterable: U,
+  obj: T,
+): Promise<Omit<T, IterableInfer<U>>> {
+  const keys = new Set(await toArray(iterable));
+  return inner(obj, keys) as Omit<T, IterableInfer<U>>;
+}
+
+/**
+ * omit
+ *
+ * Returns a partial copy of an object omitting the keys specified.
+ *
+ * @example
+ * ```ts
+ * const person = {
+ *   name: "james",
+ *   age: 40,
+ *   numberOfKids: 2,
+ *   team: "Software Development",
+ *   preferredLanguage: "Rust",
+ * };
+ *
+ * const dad = omit(["team", "preferredLanguage"], person);
+ * // { name: "james", age: 40, numberOfKids: 2 }
+ *
+ * const developer = omit(["age", "numberOfKids"], person);
+ * // { name: "james", team: "Software Development", preferredLanguage: "Rust" }
+ *
+ * // with pipe
+ * pipe(
+ *  person,
+ *  omit(["team", "preferredLanguage"]),
+ * );
+ *
+ * // if you want to use AsyncIterable as the list of property names
+ * const anonymous = await omit(toAsync(["name"] as const), person);
+ * ```
+ * see {@link https://fxts.dev/docs/pipe | pipe}, {@link https://fxts.dev/docs/toAsync | toAsync},
+ * {@link https://fxts.dev/docs/pick | pick},
+ */
+
+function omit<T extends object, U extends Iterable<keyof T>>(
+  iterable: U,
+  obj: T,
+): Omit<T, IterableInfer<U>>;
+
+function omit<T extends object, U extends AsyncIterable<keyof T>>(
+  iterable: U,
+  obj: T,
+): Promise<Omit<T, IterableInfer<U>>>;
+
+function omit<T extends object, U extends Iterable<keyof T>>(
+  iterable: U,
+): (obj: T) => Omit<T, IterableInfer<U>>;
+
+function omit<T extends object, U extends AsyncIterable<keyof T>>(
+  iterable: U,
+): (obj: T) => Promise<Omit<T, IterableInfer<U>>>;
+
+function omit<
+  T extends object,
+  U extends AsyncIterable<keyof T> | Iterable<keyof T>,
+>(
+  iterable: U,
+  obj?: T,
+):
+  | Promise<Omit<T, IterableInfer<U>>>
+  | Omit<T, IterableInfer<U>>
+  | ((
+      obj: T,
+    ) => Promise<Omit<T, IterableInfer<U>>> | Omit<T, IterableInfer<U>>) {
+  if (obj === undefined) {
+    return (obj: T) => omit(iterable as any, obj) as any;
+  }
+  if (isIterable(iterable)) {
+    return sync(iterable, obj) as Omit<T, IterableInfer<U>>;
+  } else if (isAsyncIterable(iterable)) {
+    return async(iterable, obj) as Promise<Omit<T, IterableInfer<U>>>;
+  }
+  throw new TypeError("'iterable' must be type of Iterable or AsyncIterable");
+}
+
+export default omit;
diff --git a/src/pick.ts b/src/pick.ts
new file mode 100644
index 00000000..cad24631
--- /dev/null
+++ b/src/pick.ts
@@ -0,0 +1,107 @@
+import IterableInfer from "./types/IterableInfer";
+import { isAsyncIterable, isIterable } from "./_internal/utils";
+import toArray from "./toArray";
+
+function inner<T>(obj: T, keys: Set<keyof T>) {
+  return Object.fromEntries(
+    Object.entries(obj).filter(([k]) => keys.has(k as keyof T)),
+  );
+}
+
+function sync<T extends object, U extends Iterable<keyof T>>(
+  iterable: U,
+  obj: T,
+): Pick<T, IterableInfer<U>> {
+  const keys = new Set(iterable);
+  return inner(obj, keys) as Pick<T, IterableInfer<U>>;
+}
+
+async function async<T extends object, U extends AsyncIterable<keyof T>>(
+  iterable: U,
+  obj: T,
+): Promise<Pick<T, IterableInfer<U>>> {
+  const keys = new Set(await toArray(iterable));
+  return inner(obj, keys) as Pick<T, IterableInfer<U>>;
+}
+
+/**
+ * pick
+ *
+ * Returns a partial copy of an object containing given keys.
+ *
+ * @example
+ * ```ts
+ * const person = {
+ *   name: "james",
+ *   age: 40,
+ *   numberOfKids: 2,
+ *   team: "Software Development",
+ *   preferredLanguage: "Rust",
+ * };
+ *
+ * const dad = pick(["name", "age", "numberOfKids"], person);
+ * // { name: "james", age: 40, numberOfKids: 2 }
+ *
+ * const developer = pick(["name", "team", "preferredLanguage"], person);
+ * // { name: "james", team: "Software Development", preferredLanguage: "Rust" }
+ *
+ * // with pipe
+ * pipe(
+ *  person,
+ *  pick(["name", "age", "numberOfKids"]),
+ * );
+ *
+ * // if you want to use AsyncIterable as the list of property names
+ * const anonymousDeveloper = await pick(toAsync(["preferredLanguage"] as const), person);
+ * ```
+ * see {@link https://fxts.dev/docs/pipe | pipe}, {@link https://fxts.dev/docs/toAsync | toAsync},
+ * {@link https://fxts.dev/docs/omit | omit},
+ */
+
+function pick<T extends object, U extends readonly []>(
+  iterable: U,
+  obj: T,
+): Record<string, never>;
+
+function pick<T extends object, U extends Iterable<keyof T>>(
+  iterable: U,
+  obj: T,
+): Pick<T, IterableInfer<U>>;
+
+function pick<T extends object, U extends AsyncIterable<keyof T>>(
+  iterable: U,
+  obj: T,
+): Promise<Pick<T, IterableInfer<U>>>;
+
+function pick<T extends object, U extends Iterable<keyof T>>(
+  iterable: U,
+): (obj: T) => Pick<T, IterableInfer<U>>;
+
+function pick<T extends object, U extends AsyncIterable<keyof T>>(
+  iterable: U,
+): (obj: T) => Promise<Pick<T, IterableInfer<U>>>;
+
+function pick<
+  T extends object,
+  U extends AsyncIterable<keyof T> | Iterable<keyof T>,
+>(
+  iterable: U,
+  obj?: T,
+):
+  | Promise<Pick<T, IterableInfer<U>>>
+  | Pick<T, IterableInfer<U>>
+  | ((
+      obj: T,
+    ) => Promise<Pick<T, IterableInfer<U>>> | Pick<T, IterableInfer<U>>) {
+  if (obj === undefined) {
+    return (obj: T) => pick(iterable as any, obj) as any;
+  }
+  if (isIterable(iterable)) {
+    return sync(iterable, obj);
+  } else if (isAsyncIterable(iterable)) {
+    return async(iterable, obj);
+  }
+  throw new TypeError("'iterable' must be type of Iterable or AsyncIterable");
+}
+
+export default pick;


Test patch:
diff --git a/test/Lazy/dropUntil.spec.ts b/test/Lazy/dropUntil.spec.ts
new file mode 100644
index 00000000..a458d859
--- /dev/null
+++ b/test/Lazy/dropUntil.spec.ts
@@ -0,0 +1,175 @@
+import {
+  concurrent,
+  delay,
+  dropUntil,
+  filter,
+  map,
+  pipe,
+  toArray,
+  toAsync,
+} from "../../src";
+import { Concurrent } from "../../src/Lazy/concurrent";
+import { AsyncFunctionException } from "../../src/_internal/error";
+import { callFuncAfterTime, generatorMock } from "../utils";
+
+describe("dropUntil", function () {
+  describe("sync", function () {
+    it("should be dropped elements until the value applied to callback returns truly", function () {
+      const arr = [1, 2, 3, 4, 5, 1, 2];
+      const acc = [];
+      for (const a of dropUntil((a) => a > 3, arr)) {
+        acc.push(a);
+      }
+      expect(acc).toEqual([5, 1, 2]);
+    });
+
+    it("should throw an error when the callback is asynchronous", function () {
+      const res = () => [...dropUntil(async (a) => a > 5, [1, 2, 3, 4, 5])];
+      expect(res).toThrowError(new AsyncFunctionException());
+    });
+
+    it("should be able to be used as a curried function in the pipeline", function () {
+      const res = pipe(
+        [1, 2, 3, 4, 5, 1, 2],
+        map((a) => a + 10),
+        filter((a) => a % 2 === 1),
+        dropUntil((a) => a > 13),
+        toArray,
+      );
+
+      expect(res).toEqual([11]);
+    });
+  });
+
+  describe("async", function () {
+    it("should be dropped elements until the value applied to callback returns truly", async function () {
+      const arr = [1, 2, 3, 4, 5, 1, 2];
+      const acc = [];
+      for await (const a of dropUntil((a) => a > 3, toAsync(arr))) {
+        acc.push(a);
+      }
+      expect(acc).toEqual([5, 1, 2]);
+    });
+
+    it("should be dropped elements until the value applied to async callback returns truly", async function () {
+      const arr = [1, 2, 3, 4, 5, 1, 2];
+      const acc = [];
+      for await (const a of dropUntil(async (a) => a > 3, toAsync(arr))) {
+        acc.push(a);
+      }
+      expect(acc).toEqual([5, 1, 2]);
+    });
+
+    it("should be able to be used as a curried function in the pipeline", async function () {
+      const res = await pipe(
+        [1, 2, 3, 4, 5, 1, 2],
+        toAsync,
+        map((a) => a + 10),
+        filter((a) => a % 2 === 1),
+        dropUntil((a) => a > 13),
+        toArray,
+      );
+
+      expect(res).toEqual([11]);
+    });
+
+    it("should be able to handle an error when asynchronous", async function () {
+      await expect(
+        pipe(
+          toAsync([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
+          dropUntil((a) => {
+            if (a > 5) {
+              throw new Error("err");
+            }
+            return false;
+          }),
+          toArray,
+        ),
+      ).rejects.toThrow("err");
+    });
+
+    it("should be dropped elements concurrently", async function () {
+      const fn = jest.fn();
+      callFuncAfterTime(fn, 300);
+      const res = await pipe(
+        [1, 2, 3, 4, 5, 1, 2],
+        toAsync,
+        map((a) => delay(100, a + 10)),
+        filter((a) => a % 2 === 1),
+        dropUntil((a) => a > 13),
+        concurrent(3),
+        toArray,
+      );
+      expect(fn).toBeCalled();
+      expect(res).toEqual([11]);
+    }, 350);
+
+    it("should be controlled the order when concurrency", async function () {
+      const fn = jest.fn();
+      callFuncAfterTime(fn, 1000);
+
+      const res = await pipe(
+        toAsync(
+          (function* () {
+            yield delay(500, 1);
+            yield delay(400, 2);
+            yield delay(300, 3);
+            yield delay(200, 4);
+            yield delay(100, 5);
+            yield delay(500, 11);
+            yield delay(400, 12);
+            yield delay(300, 13);
+            yield delay(200, 8);
+            yield delay(100, 9);
+          })(),
+        ),
+        dropUntil((a) => a > 12),
+        concurrent(5),
+        toArray,
+      );
+      expect(fn).toBeCalled();
+      expect(res).toEqual([8, 9]);
+    }, 1050);
+
+    it("should be able to handle an error when working concurrent", async function () {
+      await expect(
+        pipe(
+          toAsync([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
+          dropUntil((a) => {
+            if (a > 5) {
+              throw new Error("err");
+            }
+            return false;
+          }),
+          concurrent(3),
+          toArray,
+        ),
+      ).rejects.toThrow("err");
+    });
+
+    it("should be able to handle an error when working concurrent - Promise.reject", async function () {
+      await expect(
+        pipe(
+          toAsync([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
+          dropUntil((a) => {
+            if (a > 5) {
+              return Promise.reject(new Error("err"));
+            }
+            return false;
+          }),
+          concurrent(3),
+          toArray,
+        ),
+      ).rejects.toThrow("err");
+    });
+
+    it("should be passed concurrent object when job works concurrently", async function () {
+      const mock = generatorMock();
+      const iter = dropUntil((a) => a, mock);
+      const concurrent = Concurrent.of(2) as any;
+
+      await iter.next(concurrent);
+      expect((mock as any).getConcurrent()).toEqual(concurrent);
+    });
+  });
+});
diff --git a/test/omit.spec.ts b/test/omit.spec.ts
new file mode 100644
index 00000000..c019401f
--- /dev/null
+++ b/test/omit.spec.ts
@@ -0,0 +1,35 @@
+import { omit, pipe, toAsync } from "../src/index";
+
+describe("omit", function () {
+  describe("sync", function () {
+    it("should be omitted properties as given keys", function () {
+      const obj = { a: 1, b: 2, c: "3" };
+      expect(omit(["a", "c"], obj)).toEqual({ b: 2 });
+    });
+    it("should be able to be used as a curried function in the pipeline", function () {
+      const res = pipe(
+        { a: 1, b: "2", c: true },
+        omit(["a", "b"]),
+        Object.entries,
+      );
+      expect(res).toEqual([["c", true]]);
+    });
+  });
+
+  describe("async", function () {
+    it("should be omitted properties as given keys", async function () {
+      const obj = { a: 1, b: 2, c: "3" };
+      const iter = toAsync(["a", "c"] as const);
+      const res = await omit(iter, obj);
+      expect(res).toEqual({ b: 2 });
+    });
+    it("should be able to be used as a curried function in the pipeline", async function () {
+      const res = await pipe(
+        { a: 1, b: "2", c: true },
+        omit(toAsync(["a", "b"] as const)),
+        Object.entries,
+      );
+      expect(res).toEqual([["c", true]]);
+    });
+  });
+});
diff --git a/test/pick.spec.ts b/test/pick.spec.ts
new file mode 100644
index 00000000..64e7cdb0
--- /dev/null
+++ b/test/pick.spec.ts
@@ -0,0 +1,41 @@
+import { pick, pipe, toAsync } from "../src/index";
+
+describe("pick", function () {
+  describe("sync", function () {
+    it("should be picked properties as given keys", function () {
+      const obj = { a: 1, b: 2, c: "3" };
+      expect(pick(["a", "c"], obj)).toEqual({ a: 1, c: "3" });
+    });
+    it("should be able to be used as a curried function in the pipeline", function () {
+      const res = pipe(
+        { a: 1, b: "2", c: true },
+        pick(["a", "b"]),
+        Object.entries,
+      );
+      expect(res).toEqual([
+        ["a", 1],
+        ["b", "2"],
+      ]);
+    });
+  });
+
+  describe("async", function () {
+    it("should be picked properties as given keys", async function () {
+      const obj = { a: 1, b: 2, c: "3" };
+      const iter = toAsync(["a", "c"] as const);
+      const res = await pick(iter, obj);
+      expect(res).toEqual({ a: 1, c: "3" });
+    });
+    it("should be able to be used as a curried function in the pipeline", async function () {
+      const res = await pipe(
+        { a: 1, b: "2", c: true },
+        pick(toAsync(["a", "b"] as const)),
+        Object.entries,
+      );
+      expect(res).toEqual([
+        ["a", 1],
+        ["b", "2"],
+      ]);
+    });
+  });
+});
diff --git a/type-check/Lazy/dropUntil.test.ts b/type-check/Lazy/dropUntil.test.ts
new file mode 100644
index 00000000..435e96a7
--- /dev/null
+++ b/type-check/Lazy/dropUntil.test.ts
@@ -0,0 +1,24 @@
+import * as Test from "../../src/types/Test";
+import { toAsync, dropUntil, pipe } from "../../src";
+
+const { checks, check } = Test;
+
+const res1 = dropUntil((a) => a, []);
+const res2 = dropUntil((a) => a > 1, [1, 2, 3, 4]);
+const res3 = dropUntil((a) => a > 1, toAsync([1, 2, 3, 4]));
+const res4 = pipe(
+  [1, 2, 3, 4],
+  dropUntil((a) => a > 1),
+);
+const res5 = pipe(
+  toAsync([1, 2, 3, 4]),
+  dropUntil((a) => a > 1),
+);
+
+checks([
+  check<typeof res1, IterableIterator<never>, Test.Pass>(),
+  check<typeof res2, IterableIterator<number>, Test.Pass>(),
+  check<typeof res3, AsyncIterableIterator<number>, Test.Pass>(),
+  check<typeof res4, IterableIterator<number>, Test.Pass>(),
+  check<typeof res5, AsyncIterableIterator<number>, Test.Pass>(),
+]);
diff --git a/type-check/omit.test.ts b/type-check/omit.test.ts
new file mode 100644
index 00000000..2283f122
--- /dev/null
+++ b/type-check/omit.test.ts
@@ -0,0 +1,30 @@
+import * as Test from "../src/types/Test";
+import { omit, toAsync } from "../src";
+
+const { checks, check } = Test;
+
+const obj1 = {
+  a: 1,
+  b: "2",
+  c: true,
+  d: Symbol("d"),
+};
+
+type OptionalObj = {
+  a: number;
+  b?: string;
+};
+
+const res1 = omit([], obj1);
+const res2 = omit(["a", "b"], obj1);
+const res3 = omit(["a", "c"], obj1);
+const res4 = omit(toAsync(["a", "c"] as const), obj1);
+const res5 = omit(["a"], { a: 1 } as OptionalObj);
+
+checks([
+  check<typeof res1, typeof obj1, Test.Pass>(),
+  check<typeof res2, { c: boolean; d: symbol }, Test.Pass>(),
+  check<typeof res3, { b: string; d: symbol }, Test.Pass>(),
+  check<typeof res4, Promise<{ b: string; d: symbol }>, Test.Pass>(),
+  check<typeof res5, { b?: string }, Test.Pass>(),
+]);
diff --git a/type-check/pick.test.ts b/type-check/pick.test.ts
new file mode 100644
index 00000000..d024b827
--- /dev/null
+++ b/type-check/pick.test.ts
@@ -0,0 +1,30 @@
+import * as Test from "../src/types/Test";
+import { pick, toAsync } from "../src";
+
+const { checks, check } = Test;
+
+const obj1 = {
+  a: 1,
+  b: "2",
+  c: true,
+  d: Symbol("d"),
+};
+
+type OptionalObj = {
+  a: number;
+  b?: string;
+};
+
+const res1 = pick([], obj1);
+const res2 = pick(["a", "b", "d"], obj1);
+const res3 = pick(["a", "c"], obj1);
+const res4 = pick(toAsync(["a", "b"] as const), obj1);
+const res5 = pick(["a", "b"], { a: 1 } as OptionalObj);
+
+checks([
+  check<typeof res1, Record<string, never>, Test.Pass>(),
+  check<typeof res2, { a: number; b: string; d: symbol }, Test.Pass>(),
+  check<typeof res3, { a: number; c: boolean }, Test.Pass>(),
+  check<typeof res4, Promise<{ a: number; b: string }>, Test.Pass>(),
+  check<typeof res5, { a: number; b?: string }, Test.Pass>(),
+]);