Repository: gcanti/fp-ts
Pull request #880 (2019-06-05 11:54:14)

Makes array chop easier to use
This PR changes the signature of the chop function to use `NonEmptyArray` as the type of the argument of the function passed as second argument because it's called always with a `NonEmptyArray`.

This PR also adds a simple type predicate to allow narrowing down an `Array` to a `NonEmptyArray`, which is useful for while loop, if-else or ternary operator, but also in all functions where a type predicate has to be provided.


Patch:
diff --git a/docs/modules/Array.ts.md b/docs/modules/Array.ts.md
index 39841acf..9b6726e8 100644
--- a/docs/modules/Array.ts.md
+++ b/docs/modules/Array.ts.md
@@ -50,6 +50,7 @@ Adapted from https://github.com/purescript/purescript-arrays
 - [insertAt (function)](#insertat-function)
 - [intersection (function)](#intersection-function)
 - [isEmpty (function)](#isempty-function)
+- [isNonEmpty (function)](#isnonempty-function)
 - [isOutOfBound (function)](#isoutofbound-function)
 - [last (function)](#last-function)
 - [lefts (function)](#lefts-function)
@@ -172,7 +173,7 @@ value and the rest of the array.
 **Signature**
 
 ```ts
-export const chop = <A, B>(as: Array<A>, f: (as: Array<A>) => [B, Array<A>]): Array<B> => ...
+export const chop = <A, B>(as: Array<A>, f: (as: NonEmptyArray<A>) => [B, Array<A>]): Array<B> => ...
 ```
 
 **Example**
@@ -865,6 +866,16 @@ assert.strictEqual(isEmpty([]), true)
 
 Added in v1.0.0
 
+# isNonEmpty (function)
+
+Test whether an array is non empty narrowing down the type to `NonEmptyArray<A>`
+
+**Signature**
+
+```ts
+export const isNonEmpty = <A>(as: Array<A>): as is NonEmptyArray<A> => ...
+```
+
 # isOutOfBound (function)
 
 Test whether an array contains a particular index
diff --git a/dtslint/ts3.1/index.ts b/dtslint/ts3.1/index.ts
index 060ab1fc..de60859a 100644
--- a/dtslint/ts3.1/index.ts
+++ b/dtslint/ts3.1/index.ts
@@ -412,6 +412,12 @@ const nea2v1concat3 = array1.concat(nea2v1) // $ExpectType string[]
 
 const nea2v1sort1 = nea2v1.sort(Or.ordString.compare) // $ExpectType NonEmptyArray<string>
 
+if (A.isNonEmpty(array1)) {
+  array1 // $ExpectType NonEmptyArray<string>
+} else {
+  array1 // $ExpectType string[]
+}
+
 //
 // function
 //
diff --git a/src/Array.ts b/src/Array.ts
index 7874ae1e..03cbf4b2 100644
--- a/src/Array.ts
+++ b/src/Array.ts
@@ -439,6 +439,11 @@ export const isEmpty = <A>(as: Array<A>): boolean => {
   return as.length === 0
 }
 
+/**
+ * Test whether an array is non empty narrowing down the type to `NonEmptyArray<A>`
+ */
+export const isNonEmpty = <A>(as: Array<A>): as is NonEmptyArray<A> => as.length > 0
+
 /**
  * Test whether an array contains a particular index
  *
@@ -1401,10 +1406,10 @@ const wilt = <F>(
  *
  * @since 1.10.0
  */
-export const chop = <A, B>(as: Array<A>, f: (as: Array<A>) => [B, Array<A>]): Array<B> => {
+export const chop = <A, B>(as: Array<A>, f: (as: NonEmptyArray<A>) => [B, Array<A>]): Array<B> => {
   const result: Array<B> = []
   let cs: Array<A> = as
-  while (cs.length > 0) {
+  while (isNonEmpty(cs)) {
     const [b, c] = f(cs)
     result.push(b)
     cs = c
diff --git a/src/NonEmptyArray2v.ts b/src/NonEmptyArray2v.ts
index 70672e63..ca41e96f 100644
--- a/src/NonEmptyArray2v.ts
+++ b/src/NonEmptyArray2v.ts
@@ -96,7 +96,7 @@ export function max<A>(ord: Ord<A>): (nea: NonEmptyArray<A>) => A {
  * @since 1.15.0
  */
 export function fromArray<A>(as: Array<A>): Option<NonEmptyArray<A>> {
-  return as.length > 0 ? some(as as any) : none
+  return A.isNonEmpty(as) ? some(as) : none
 }
 
 /**


Test patch:
diff --git a/test/Array.ts b/test/Array.ts
index ac718ca5..0173c18a 100644
--- a/test/Array.ts
+++ b/test/Array.ts
@@ -64,7 +64,8 @@ import {
   unsafeUpdateAt,
   findFirstMap,
   findLastMap,
-  getShow
+  getShow,
+  isNonEmpty
 } from '../src/Array'
 import { left, right } from '../src/Either'
 import { fold as foldMonoid, monoidSum, monoidString } from '../src/Monoid'
@@ -155,6 +156,11 @@ describe('Array', () => {
     assert.strictEqual(isEmpty([]), true)
   })
 
+  it('isNotEmpty', () => {
+    assert.strictEqual(isNonEmpty(as), true)
+    assert.strictEqual(isNonEmpty([]), false)
+  })
+
   it('index', () => {
     // tslint:disable-next-line: deprecation
     assert.deepStrictEqual(index(1, as), some(2))