From a525a46bca42cb8f58116f6043919d15fd52712a Mon Sep 17 00:00:00 2001
From: Matei Adriel <rafaeladriel11@gmail.com>
Date: Wed, 25 Dec 2019 15:40:47 +0200
Subject: [PATCH] typescript(option): feat: added a first helper

Signed-off-by: prescientmoon <git@moonythm.dev>
---
 typescript/option/src/helpers/external.ts   |  1 +
 typescript/option/src/helpers/first.test.ts | 32 +++++++++++++++++++++
 typescript/option/src/helpers/first.ts      | 17 +++++++++++
 3 files changed, 50 insertions(+)
 create mode 100644 typescript/option/src/helpers/first.test.ts
 create mode 100644 typescript/option/src/helpers/first.ts

diff --git a/typescript/option/src/helpers/external.ts b/typescript/option/src/helpers/external.ts
index 36a2cc5..a08193e 100644
--- a/typescript/option/src/helpers/external.ts
+++ b/typescript/option/src/helpers/external.ts
@@ -3,6 +3,7 @@ export * from './bindAsync'
 export * from './count'
 export * from './exists'
 export * from './filter'
+export * from './first'
 export * from './flat'
 export * from './fold'
 export * from './foldback'
diff --git a/typescript/option/src/helpers/first.test.ts b/typescript/option/src/helpers/first.test.ts
new file mode 100644
index 0000000..3a410cf
--- /dev/null
+++ b/typescript/option/src/helpers/first.test.ts
@@ -0,0 +1,32 @@
+import { constantly } from '@thi.ng/compose'
+import { expect } from 'chai'
+import { someX } from '../../test/constants'
+import { None, Option } from '../types'
+import { first } from './first'
+
+describe('The first helper', () => {
+    it('should return the first Some if there is any', () => {
+        // act
+        const head = first([someX, None])
+        const middle = first([None, someX, None])
+        const tail = first([None, someX])
+
+        // assert
+        expect(head).to.equal(someX)
+        expect(middle).to.equal(someX)
+        expect(tail).to.equal(someX)
+    })
+
+    it("should return None if there isn't any Some", () => {
+        // arrange
+        const array: Option<unknown>[] = Array(50)
+            .fill(1)
+            .map(constantly(None))
+
+        // act
+        const result = first(array)
+
+        // assert
+        expect(result).to.equal(None)
+    })
+})
diff --git a/typescript/option/src/helpers/first.ts b/typescript/option/src/helpers/first.ts
new file mode 100644
index 0000000..9a03d12
--- /dev/null
+++ b/typescript/option/src/helpers/first.ts
@@ -0,0 +1,17 @@
+import { isSome } from './isSome'
+import { Option, None } from '../types'
+
+/**
+ * Returns the first Some in an iterable. If there isn't any returns None.
+ *
+ * @param elemenets The elements to find the first Some in.
+ */
+export const first = <T>(elemenets: Iterable<Option<T>>) => {
+    for (const option of elemenets) {
+        if (isSome(option)) {
+            return option
+        }
+    }
+
+    return None
+}