diff --git a/src/Enumerable.ts b/src/Enumerable.ts
index fa12617..eb9fc53 100644
--- a/src/Enumerable.ts
+++ b/src/Enumerable.ts
@@ -1,47 +1,71 @@
-import { from } from './functions/from';
-import { aggregate } from './functions/aggregate';
-import { all } from './functions/all';
-import { any } from './functions/any';
-import { append } from './functions/append';
-import { atLeast } from './functions/atLeast';
-import { atMost } from './functions/atMost';
-import { concat } from './functions/concat';
-import { contains } from './functions/contains';
-import { count } from './functions/count';
-import { defaultIfEmpty } from './functions/defaultIfEmpty';
-import { distinct, distinctBy } from './functions/distinct';
-import { elementAt, elementAtOrDefault } from './functions/elementAt';
-import { empty } from './functions/empty';
-import { endsWith } from './functions/endsWith';
-import { except, exceptBy } from './functions/except';
-import { first, firstOrDefault } from './functions/first';
-import { forEach } from './functions/forEach';
-import { groupBy } from './functions/groupBy';
-import { intersect, intersectBy } from './functions/intersect';
-import { last, lastOrDefault } from './functions/last';
-import { max, maxBy } from './functions/max';
-import { ofType } from './functions/ofType';
-import { orderBy } from './functions/orderBy';
-import { prepend } from './functions/prepend';
-import { quantile } from './functions/quantile';
-import { range } from './functions/range';
-import { repeat } from './functions/repeat';
-import { reverse } from './functions/reverse';
-import { select, selectMany } from './functions/select';
-import { sequenceEqual } from './functions/sequenceEqual';
-import { shuffle } from './functions/shuffle';
-import { skip, skipLast, skipWhile } from './functions/skip';
-import { startsWith } from './functions/startsWith';
-import { sum } from './functions/sum';
-import { take, takeEvery, takeLast, takeWhile } from './functions/take';
-import { thenBy } from './functions/thenBy';
-import { toMap } from './functions/toMap';
-import { toObject } from './functions/toObject';
-import { toSet } from './functions/toSet';
-import { union, unionBy } from './functions/union';
-import { where } from './functions/where';
-import { zip } from './functions/zip';
-import { Comparer, EqualityComparer } from './types';
+import {
+  from,
+  empty,
+  range,
+  repeat,
+  aggregate,
+  all,
+  any,
+  append,
+  asEnumerable,
+  atLeast,
+  atMost,
+  average,
+  chunk,
+  concat,
+  EqualityComparer,
+  contains,
+  count,
+  defaultIfEmpty,
+  distinct,
+  distinctBy,
+  elementAt,
+  elementAtOrDefault,
+  endsWith,
+  except,
+  exceptBy,
+  first,
+  firstOrDefault,
+  forEach,
+  groupBy,
+  intersect,
+  intersectBy,
+  last,
+  lastOrDefault,
+  max,
+  maxBy,
+  min,
+  minBy,
+  ofType,
+  Comparer,
+  orderBy,
+  pipe,
+  prepend,
+  quantile,
+  reverse,
+  select,
+  selectMany,
+  sequenceEqual,
+  shuffle,
+  skip,
+  skipLast,
+  skipWhile,
+  startsWith,
+  sum,
+  take,
+  takeEvery,
+  takeLast,
+  takeWhile,
+  toArray,
+  toMap,
+  toObject,
+  toSet,
+  union,
+  unionBy,
+  where,
+  zip,
+  thenBy
+} from '.';
 
 export class Enumerable<TSource> implements Iterable<TSource> {
   private readonly srcGenerator: () => Generator<TSource>;
@@ -87,7 +111,7 @@ export class Enumerable<TSource> implements Iterable<TSource> {
     return this.srcGenerator();
   }
 
-  public aggregate<T>(aggregator: (prev: T, curr: T, index: number) => T): T;
+  public aggregate(aggregator: (prev: TSource, curr: TSource, index: number) => TSource): TSource;
   public aggregate<TAccumulate>(
     aggregator: (prev: TAccumulate, curr: TSource, index: number) => TAccumulate,
     seed: TAccumulate
@@ -112,7 +136,7 @@ export class Enumerable<TSource> implements Iterable<TSource> {
   }
 
   public asEnumerable(): Enumerable<TSource> {
-    return new Enumerable(this.srcGenerator);
+    return asEnumerable(this);
   }
 
   public atLeast(count: number, predicate?: (item: TSource, index: number) => boolean): boolean {
@@ -124,13 +148,11 @@ export class Enumerable<TSource> implements Iterable<TSource> {
   }
 
   public average(selector?: (item: TSource) => number): number {
-    return this.sum(selector) / this.count();
+    return average(this, selector);
   }
 
   public chunk(chunkSize: number): Enumerable<Enumerable<TSource>> {
-    return this.select((x, i) => ({ index: i, value: x }))
-      .groupBy(x => Math.floor(x.index / chunkSize))
-      .select(x => x.select(v => v.value));
+    return chunk(this, chunkSize);
   }
 
   public concat(second: Iterable<TSource>): Enumerable<TSource> {
@@ -256,15 +278,11 @@ export class Enumerable<TSource> implements Iterable<TSource> {
   public min(): TSource;
   public min<TResult>(selector: (item: TSource) => TResult): TResult;
   public min<TResult>(selector?: (item: TSource) => TResult): TSource | TResult {
-    if (!selector) {
-      return this.aggregate((prev, curr) => (prev < curr ? prev : curr));
-    }
-
-    return this.select(selector).aggregate((prev, curr) => (prev < curr ? prev : curr));
+    return min(this, selector);
   }
 
   public minBy<TKey>(keySelector: (item: TSource) => TKey): TSource {
-    return this.aggregate((prev, curr) => (keySelector(prev) <= keySelector(curr) ? prev : curr));
+    return minBy(this, keySelector);
   }
 
   public ofType<TResult>(type: new (...params: unknown[]) => TResult): Enumerable<TResult> {
@@ -282,6 +300,10 @@ export class Enumerable<TSource> implements Iterable<TSource> {
     return orderBy(this, false, selector, comparer);
   }
 
+  public pipe(action: (item: TSource, index: number) => void): Enumerable<TSource> {
+    return pipe(this, action);
+  }
+
   public prepend(item: TSource): Enumerable<TSource> {
     return prepend(this, item);
   }
@@ -362,7 +384,7 @@ export class Enumerable<TSource> implements Iterable<TSource> {
   }
 
   public toArray(): TSource[] {
-    return [...this];
+    return toArray(this);
   }
 
   public toLookup(): unknown {
diff --git a/src/__tests__/ofType.ts b/src/__tests__/ofType.ts
new file mode 100644
index 0000000..6157a29
--- /dev/null
+++ b/src/__tests__/ofType.ts
@@ -0,0 +1,32 @@
+import { Enumerable, ofType, TypeOfMember } from '..';
+
+describe('ofType', () => {
+  it.each([[1, 2, 3], new Set([1, 2, 3]), '123', new Map()])('should return an Enumerable', src => {
+    const result = ofType<unknown, string>(src, 'string');
+
+    expect(result).toBeInstanceOf(Enumerable);
+  });
+
+  it.each([
+    [[1, 'b', 'c', false], 'string', ['b', 'c']],
+    [[1, 'b', 'c', false, 2, true], 'number', [1, 2]],
+    [[1, 'b', 'c', false, 2, true], 'boolean', [false, true]]
+  ])('should only return the specified type', (src, type, expected) => {
+    const result = ofType(src, type as TypeOfMember).toArray();
+
+    expect(result).toEqual(expected);
+  });
+
+  it('should only return instances of passed class', () => {
+    class Test {}
+
+    const a = new Test();
+    const b = new Test();
+
+    const items = [1, 3, 'sadf', a, false, null, undefined, b, NaN];
+
+    const result = ofType(items, Test).toArray();
+
+    expect(result).toEqual([a, b]);
+  });
+});
diff --git a/src/__tests__/pipe.ts b/src/__tests__/pipe.ts
new file mode 100644
index 0000000..4b7e3e4
--- /dev/null
+++ b/src/__tests__/pipe.ts
@@ -0,0 +1,35 @@
+import { Enumerable, pipe } from '..';
+
+describe('pipe', () => {
+  it.each([[1, 2, 3], new Set([1, 2, 3]), '123', new Map()])('should return an Enumerable', src => {
+    const result = pipe<unknown>(src, () => {});
+
+    expect(result).toBeInstanceOf(Enumerable);
+  });
+
+  it('should call action for each item', () => {
+    const action = jest.fn();
+
+    const items = [1, 2, 3];
+
+    const _ = pipe(items, action).toArray();
+
+    expect(action).toHaveBeenCalledTimes(items.length);
+  });
+
+  it('should have deferred execution', () => {
+    const action = jest.fn();
+
+    const items = [1, 2, 3];
+
+    const result = pipe(items, action);
+
+    expect(action).toHaveBeenCalledTimes(0);
+
+    items.push(4);
+
+    const _ = result.toArray();
+
+    expect(action).toHaveBeenCalledTimes(items.length);
+  });
+});
diff --git a/src/functions/aggregate.ts b/src/functions/aggregate.ts
index 1b88f3a..ea1597f 100644
--- a/src/functions/aggregate.ts
+++ b/src/functions/aggregate.ts
@@ -1,3 +1,17 @@
+export function aggregate<TSource>(
+  src: Iterable<TSource>,
+  aggregator: (prev: TSource, curr: TSource, index: number) => TSource
+): TSource;
+export function aggregate<TSource, TAccumulate>(
+  src: Iterable<TSource>,
+  aggregator: (prev: TAccumulate, curr: TSource, index: number) => TAccumulate,
+  seed: TAccumulate
+): TAccumulate;
+export function aggregate<TSource, TAccumulate>(
+  src: Iterable<TSource>,
+  aggregator: (prev: TAccumulate | TSource, curr: TSource, index: number) => TAccumulate | TSource,
+  seed?: TAccumulate | TSource
+): TAccumulate | TSource;
 export function aggregate<TSource, TAccumulate>(
   src: Iterable<TSource>,
   aggregator: (prev: TAccumulate | TSource, curr: TSource, index: number) => TAccumulate | TSource,
diff --git a/src/functions/asEnumerable.ts b/src/functions/asEnumerable.ts
new file mode 100644
index 0000000..b2d7a6e
--- /dev/null
+++ b/src/functions/asEnumerable.ts
@@ -0,0 +1,5 @@
+import { Enumerable } from '../Enumerable';
+
+export function asEnumerable<TSource>(src: Iterable<TSource>): Enumerable<TSource> {
+  return new Enumerable(src);
+}
diff --git a/src/functions/average.ts b/src/functions/average.ts
new file mode 100644
index 0000000..b309f77
--- /dev/null
+++ b/src/functions/average.ts
@@ -0,0 +1,6 @@
+import { count } from './count';
+import { sum } from './sum';
+
+export function average<TSource>(src: Iterable<TSource>, selector?: (item: TSource) => number): number {
+  return sum(src, selector) / count(src);
+}
diff --git a/src/functions/chunk.ts b/src/functions/chunk.ts
new file mode 100644
index 0000000..e3bf2f5
--- /dev/null
+++ b/src/functions/chunk.ts
@@ -0,0 +1,8 @@
+import { Enumerable } from '../Enumerable';
+import { select } from './select';
+
+export function chunk<TSource>(src: Iterable<TSource>, chunkSize: number): Enumerable<Enumerable<TSource>> {
+  return select(src, (x, i) => ({ index: i, value: x }))
+    .groupBy(x => Math.floor(x.index / chunkSize))
+    .select(x => x.select(v => v.value));
+}
diff --git a/src/functions/index.ts b/src/functions/index.ts
new file mode 100644
index 0000000..d75d644
--- /dev/null
+++ b/src/functions/index.ts
@@ -0,0 +1,49 @@
+export * from './aggregate';
+export * from './all';
+export * from './any';
+export * from './append';
+export * from './asEnumerable';
+export * from './atLeast';
+export * from './atMost';
+export * from './average';
+export * from './chunk';
+export * from './concat';
+export * from './contains';
+export * from './count';
+export * from './defaultIfEmpty';
+export * from './distinct';
+export * from './elementAt';
+export * from './empty';
+export * from './endsWith';
+export * from './except';
+export * from './first';
+export * from './forEach';
+export * from './from';
+export * from './groupBy';
+export * from './intersect';
+export * from './last';
+export * from './max';
+export * from './min';
+export * from './ofType';
+export * from './orderBy';
+export * from './pipe';
+export * from './prepend';
+export * from './quantile';
+export * from './range';
+export * from './repeat';
+export * from './reverse';
+export * from './select';
+export * from './sequenceEqual';
+export * from './shuffle';
+export * from './skip';
+export * from './startsWith';
+export * from './sum';
+export * from './take';
+export * from './thenBy';
+export * from './toArray';
+export * from './toMap';
+export * from './toObject';
+export * from './toSet';
+export * from './union';
+export * from './where';
+export * from './zip';
diff --git a/src/functions/min.ts b/src/functions/min.ts
new file mode 100644
index 0000000..92704e4
--- /dev/null
+++ b/src/functions/min.ts
@@ -0,0 +1,20 @@
+import { aggregate } from './aggregate';
+import { select } from './select';
+
+export function min<TSource>(src: Iterable<TSource>): TSource;
+export function min<TSource, TResult>(src: Iterable<TSource>, selector: (item: TSource) => TResult): TResult;
+export function min<TSource, TResult>(src: Iterable<TSource>, selector?: (item: TSource) => TResult): TSource | TResult;
+export function min<TSource, TResult>(
+  src: Iterable<TSource>,
+  selector?: (item: TSource) => TResult
+): TSource | TResult {
+  if (!selector) {
+    return aggregate(src, (prev, curr) => (prev < curr ? prev : curr));
+  }
+
+  return select(src, selector).aggregate((prev, curr) => (prev < curr ? prev : curr));
+}
+
+export function minBy<TSource, TKey>(src: Iterable<TSource>, keySelector: (item: TSource) => TKey): TSource {
+  return aggregate(src, (prev, curr) => (keySelector(prev) <= keySelector(curr) ? prev : curr));
+}
diff --git a/src/functions/ofType.ts b/src/functions/ofType.ts
index c0e5a2e..cb32aaa 100644
--- a/src/functions/ofType.ts
+++ b/src/functions/ofType.ts
@@ -1,13 +1,29 @@
+import { TypeOfMember } from '../types';
 import { Enumerable } from '../Enumerable';
 
 export function ofType<TSource, TResult>(
   src: Iterable<TSource>,
   type: new (...params: unknown[]) => TResult
-): Enumerable<TResult> {
-  function* generator(): Generator<TResult> {
+): Enumerable<TResult>;
+export function ofType<TSource, TResult>(src: Iterable<TSource>, type: TypeOfMember): Enumerable<TResult>;
+// export function ofType<TSource, TResult>(
+//   src: Iterable<TSource>,
+//   type: (new (...params: unknown[]) => TResult) | TypeOfMember
+// ): Enumerable<TResult | TSource>;
+export function ofType<TSource, TResult>(
+  src: Iterable<TSource>,
+  type: (new (...params: unknown[]) => TResult) | TypeOfMember
+): Enumerable<TResult | TSource> {
+  function* generator(): Generator<TResult | TSource> {
     for (const item of src) {
-      if (item instanceof type) {
-        yield item;
+      if (typeof type === 'string') {
+        if (typeof item === type) {
+          yield item;
+        }
+      } else {
+        if (item instanceof type) {
+          yield item;
+        }
       }
     }
   }
diff --git a/src/functions/pipe.ts b/src/functions/pipe.ts
new file mode 100644
index 0000000..edb2a64
--- /dev/null
+++ b/src/functions/pipe.ts
@@ -0,0 +1,19 @@
+import { Enumerable } from '../Enumerable';
+
+export function pipe<TSource>(
+  src: Iterable<TSource>,
+  action: (item: TSource, index: number) => void
+): Enumerable<TSource> {
+  function* generator(): Generator<TSource> {
+    let i = 0;
+
+    for (const item of src) {
+      action(item, i);
+      yield item;
+
+      i++;
+    }
+  }
+
+  return new Enumerable(generator);
+}
diff --git a/src/functions/sum.ts b/src/functions/sum.ts
index 5aa8fb3..5740a9f 100644
--- a/src/functions/sum.ts
+++ b/src/functions/sum.ts
@@ -11,5 +11,5 @@ export function sum<TSource>(src: Iterable<TSource>, selector?: (item: TSource)
     });
   }
 
-  return aggregate(src, (prev, curr) => (prev as number) + selector(curr), 0) as number;
+  return aggregate(src, (prev, curr) => prev + selector(curr), 0);
 }
diff --git a/src/functions/toArray.ts b/src/functions/toArray.ts
new file mode 100644
index 0000000..dcd9896
--- /dev/null
+++ b/src/functions/toArray.ts
@@ -0,0 +1,3 @@
+export function toArray<TSource>(src: Iterable<TSource>): TSource[] {
+  return [...src];
+}
diff --git a/src/functions/toMap.ts b/src/functions/toMap.ts
index 703e7bb..ed6eb35 100644
--- a/src/functions/toMap.ts
+++ b/src/functions/toMap.ts
@@ -1,3 +1,14 @@
+export function toMap<TSource, TKey>(src: Iterable<TSource>, keySelector: (item: TSource) => TKey): Map<TKey, TSource>;
+export function toMap<TSource, TKey, TValue>(
+  src: Iterable<TSource>,
+  keySelector: (item: TSource) => TKey,
+  valueSelector: (item: TSource) => TValue
+): Map<TKey, TValue>;
+export function toMap<TSource, TKey, TValue>(
+  src: Iterable<TSource>,
+  keySelector: (item: TSource) => TKey,
+  valueSelector?: (item: TSource) => TValue
+): Map<TKey, TSource | TValue>;
 export function toMap<TSource, TKey, TValue>(
   src: Iterable<TSource>,
   keySelector: (item: TSource) => TKey,
diff --git a/src/functions/toObject.ts b/src/functions/toObject.ts
index d43ecb4..2ced33b 100644
--- a/src/functions/toObject.ts
+++ b/src/functions/toObject.ts
@@ -1,3 +1,17 @@
+export function toObject<TSource>(
+  src: Iterable<TSource>,
+  keySelector: (item: TSource) => string
+): Record<string, TSource>;
+export function toObject<TSource, TValue>(
+  src: Iterable<TSource>,
+  keySelector: (item: TSource) => string,
+  valueSelector: (item: TSource) => TValue
+): Record<string, TValue>;
+export function toObject<TSource, TValue>(
+  src: Iterable<TSource>,
+  keySelector: (item: TSource) => string,
+  valueSelector?: (item: TSource) => TValue
+): Record<string, TSource | TValue>;
 export function toObject<TSource, TValue>(
   src: Iterable<TSource>,
   keySelector: (item: TSource) => string,
diff --git a/src/functions/zip.ts b/src/functions/zip.ts
index 0551844..417895c 100644
--- a/src/functions/zip.ts
+++ b/src/functions/zip.ts
@@ -1,5 +1,19 @@
 import { Enumerable } from '../Enumerable';
 
+export function zip<TSource, TSecond>(
+  src: Iterable<TSource>,
+  second: Iterable<TSecond>
+): Enumerable<[TSource, TSecond]>;
+export function zip<TSource, TSecond, TResult>(
+  src: Iterable<TSource>,
+  second: Iterable<TSecond>,
+  resultSelector: (first: TSource, second: TSecond) => TResult
+): Enumerable<TResult>;
+export function zip<TSource, TSecond, TResult>(
+  src: Iterable<TSource>,
+  second: Iterable<TSecond>,
+  resultSelector?: (first: TSource, second: TSecond) => TResult
+): Enumerable<[TSource, TSecond] | TResult>;
 export function zip<TSource, TSecond, TResult>(
   src: Iterable<TSource>,
   second: Iterable<TSecond>,
diff --git a/src/index.ts b/src/index.ts
index 96dc20f..0d3caa4 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,3 +1,3 @@
 export * from './types';
-export * from './functions/from';
 export * from './Enumerable';
+export * from './functions';
diff --git a/src/types.ts b/src/types.ts
index 66d8da9..91503e8 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -1,3 +1,5 @@
 export type EqualityComparer<T> = (a: T, b: T) => boolean;
 
 export type Comparer<T> = (a: T, b: T) => number;
+
+export type TypeOfMember = 'string' | 'number' | 'boolean' | 'bigint' | 'function' | 'object' | 'symbol' | 'undefined';