Repository: char0n/ramda-adjunct
Pull request #1848 (2021-04-12 10:09:48)

Add isSentinelValue
This PR adds a predicate to determine if a value is a sentinel value. #793 

skShekhar: @char0n Can you review this PR
char0n: @skShekhar thanks! I'll provide a review ASAP.

Patch:
diff --git a/src/index.js b/src/index.js
index 7314de6b5c..1898ecbb09 100644
--- a/src/index.js
+++ b/src/index.js
@@ -91,6 +91,7 @@ export { default as isError } from './isError';
 export { default as isNaturalNumber } from './isNaturalNumber';
 export { default as isPrimitive } from './isPrimitive';
 export { default as isNotPrimitive } from './isNotPrimitive';
+export { default as isSentinelValue } from './isSentinelValue';
 // Function
 export { default as stubUndefined } from './stubUndefined';
 export { default as stubNull } from './stubNull';
diff --git a/src/isSentinelValue.js b/src/isSentinelValue.js
new file mode 100644
index 0000000000..d01d225dd3
--- /dev/null
+++ b/src/isSentinelValue.js
@@ -0,0 +1,26 @@
+import { curryN } from 'ramda';
+
+import isInteger32 from './isInteger32';
+
+/**
+ * Checks whether the passed value is {@link https://github.com/getify/You-Dont-Know-JS/blob/9959fc904d584bbf0b02cf41c192f74ff4238581/types-grammar/ch4.md#the-curious-case-of-the-|a sentinel value}.
+ *
+ * @func isSentinelValue
+ * @memberOf RA
+ * @since {@link https://char0n.github.io/ramda-adjunct/2.33.0|v2.33.0}
+ * @category Type
+ * @sig * -> Boolean
+ * @param {*} val The value to test
+ * @return {boolean}
+ * @example
+ *
+ * RA.isSentinelValue(-1); //=> true
+ *
+ * RA.isSentinelValue('-1'); //=> false
+ * RA.isSentinelValue(1); //=> false
+ * RA.isSentinelValue([-1]); //=> false
+ */
+// eslint-disable-next-line no-bitwise
+const isSentinelValue = curryN(1, (val) => isInteger32(val) && ~val === 0);
+
+export default isSentinelValue;
diff --git a/types/index.d.ts b/types/index.d.ts
index fa1714a14f..e80ac31261 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -455,6 +455,12 @@ declare namespace RamdaAdjunct {
          */
         isSparseArray(val: any): boolean;
 
+        /**
+         * Checks whether the passed value is
+         * {@link https://github.com/getify/You-Dont-Know-JS/blob/9959fc904d584bbf0b02cf41c192f74ff4238581/types-grammar/ch4.md#the-curious-case-of-the-|a sentinel value}.
+         */
+        isSentinelValue(val: any): boolean;
+
         /**
          * A function that returns `undefined`.
          */


Test patch:
diff --git a/test/isSentinelValue.js b/test/isSentinelValue.js
new file mode 100644
index 0000000000..cc5292432d
--- /dev/null
+++ b/test/isSentinelValue.js
@@ -0,0 +1,40 @@
+import * as R from 'ramda';
+import { assert } from 'chai';
+
+import * as RA from '../src';
+import MAX_SAFE_INTEGER from '../src/internal/ponyfills/Number.MAX_SAFE_INTEGER';
+import MIN_SAFE_INTEGER from '../src/internal/ponyfills/Number.MIN_SAFE_INTEGER';
+
+describe('isSentinelValue', function () {
+  it('should return true for sentinel value', function () {
+    assert.isTrue(RA.isSentinelValue(-1));
+    assert.isTrue(RA.isSentinelValue(-1.0));
+  });
+
+  it('should return false for a non sentinel value', function () {
+    assert.isFalse(RA.isSentinelValue('-1'));
+    assert.isFalse(RA.isSentinelValue(new Number(-1)));
+    assert.isFalse(RA.isSentinelValue(Object(-1)));
+    assert.isFalse(RA.isSentinelValue(-1.00001));
+    assert.isFalse(RA.isSentinelValue(1));
+    assert.isFalse(RA.isSentinelValue(MIN_SAFE_INTEGER));
+    assert.isFalse(RA.isSentinelValue(MAX_SAFE_INTEGER));
+    assert.isFalse(RA.isSentinelValue(Number.MAX_VALUE));
+    assert.isFalse(RA.isSentinelValue(Number.MIN_VALUE));
+    assert.isFalse(RA.isSentinelValue(null));
+    assert.isFalse(RA.isSentinelValue(undefined));
+    assert.isFalse(RA.isSentinelValue(NaN));
+    assert.isFalse(RA.isSentinelValue(Infinity));
+    assert.isFalse(RA.isSentinelValue(-Infinity));
+    assert.isFalse(RA.isSentinelValue(true));
+    assert.isFalse(RA.isSentinelValue([]));
+    assert.isFalse(RA.isSentinelValue([-1]));
+    assert.isFalse(RA.isSentinelValue({}));
+  });
+
+  it('should support placeholder to specify "gaps"', function () {
+    const isSentinelValue = RA.isSentinelValue(R.__);
+    assert.isTrue(isSentinelValue(-1));
+    assert.isFalse(isSentinelValue(1));
+  });
+});
diff --git a/types/test/isSentinelValue.ts b/types/test/isSentinelValue.ts
new file mode 100644
index 0000000000..ec62642e8e
--- /dev/null
+++ b/types/test/isSentinelValue.ts
@@ -0,0 +1,15 @@
+import * as RA from 'ramda-adjunct';
+
+RA.isSentinelValue(-1); // $ExpectType boolean
+RA.isSentinelValue(null); // $ExpectType boolean
+RA.isSentinelValue(true); // $ExpectType boolean
+RA.isSentinelValue(NaN); // $ExpectType boolean
+RA.isSentinelValue({}); // $ExpectType boolean
+RA.isSentinelValue([]); // $ExpectType boolean
+RA.isSentinelValue(() => {}); // $ExpectType boolean
+RA.isSentinelValue('-1'); // $ExpectType boolean
+RA.isSentinelValue(0.1); // $ExpectType boolean
+RA.isSentinelValue(Object(-1)); // $ExpectType boolean
+RA.isSentinelValue(Number(-1)); // $ExpectType boolean
+RA.isSentinelValue(Infinity); // $ExpectType boolean
+RA.isSentinelValue(Number.MAX_VALUE); // $ExpectType boolean