spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
Moving casting functions into TypeCaster, array functions into Filter
author
Ben Vogt <[email protected]>
date
2017-02-16 03:10:00
stats
6 file(s) changed, 457 insertions(+), 381 deletions(-)
files
src/RawFormulas/Logical.ts
src/RawFormulas/Math.ts
src/RawFormulas/Misc.ts
src/RawFormulas/RawFormulas.ts
src/RawFormulas/Utils.ts
tests/FormulasTest.ts
   1diff --git a/src/RawFormulas/Logical.ts b/src/RawFormulas/Logical.ts
   2index 54d0a90..2500c39 100644
   3--- a/src/RawFormulas/Logical.ts
   4+++ b/src/RawFormulas/Logical.ts
   5@@ -1,4 +1,4 @@
   6-import { checkArgumentsAtLeastLength, checkArgumentsLength, valueToString, valueToBoolean } from "./Utils"
   7+import { ArgsChecker, Filter, TypeCaster } from "./Utils"
   8 import { CellError } from "../Errors"
   9 import * as ERRORS from "../Errors"
  10 
  11@@ -9,7 +9,7 @@ import * as ERRORS from "../Errors"
  12  * @constructor
  13  */
  14 var AND = function (...values) {
  15-  checkArgumentsAtLeastLength(values, 1);
  16+  ArgsChecker.checkAtLeastLength(values, 1);
  17   var result = true;
  18   for (var i = 0; i < values.length; i++) {
  19     if (typeof values[i] === "string") {
  20@@ -35,7 +35,7 @@ var AND = function (...values) {
  21  * @constructor
  22  */
  23 var EXACT = function (...values) {
  24-  checkArgumentsLength(values, 2);
  25+  ArgsChecker.checkLength(values, 2);
  26   var one = values[0];
  27   var two = values[1];
  28   if (one instanceof Array) {
  29@@ -48,8 +48,8 @@ var EXACT = function (...values) {
  30       throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
  31     }
  32   }
  33-  one = valueToString(one);
  34-  two = valueToString(two);
  35+  one = TypeCaster.valueToString(one);
  36+  two = TypeCaster.valueToString(two);
  37   return one === two;
  38 };
  39 
  40@@ -78,7 +78,7 @@ var FALSE = function () : boolean {
  41  * @constructor
  42  */
  43 var NOT = function (...values) : boolean {
  44-  checkArgumentsLength(values, 1);
  45+  ArgsChecker.checkLength(values, 1);
  46   var X = values[0];
  47   if (typeof(X) === "boolean") {
  48     return !X;
  49@@ -108,7 +108,7 @@ var NOT = function (...values) : boolean {
  50  * @constructor
  51  */
  52 var OR = function (...values) {
  53-  checkArgumentsAtLeastLength(values, 1);
  54+  ArgsChecker.checkAtLeastLength(values, 1);
  55   for (var i = 0; i < values.length; i++) {
  56     if (values[i] instanceof Array) {
  57       if (values[i].length === 0) {
  58@@ -117,7 +117,7 @@ var OR = function (...values) {
  59       if (OR.apply(this, values[i])) {
  60         return true;
  61       }
  62-    } else if (valueToBoolean(values[i])) {
  63+    } else if (TypeCaster.valueToBoolean(values[i])) {
  64       return true;
  65     }
  66   }
  67@@ -131,7 +131,7 @@ var OR = function (...values) {
  68  * @constructor
  69  */
  70 var XOR = function (...values) {
  71-  checkArgumentsAtLeastLength(values, 1);
  72+  ArgsChecker.checkAtLeastLength(values, 1);
  73   var alreadyTruthy = false;
  74   for (var i = 0; i < values.length; i++) {
  75     if (values[i] instanceof Array) {
  76@@ -144,7 +144,7 @@ var XOR = function (...values) {
  77         }
  78         alreadyTruthy = true;
  79       }
  80-    } else if (valueToBoolean(values[i])) {
  81+    } else if (TypeCaster.valueToBoolean(values[i])) {
  82       if (alreadyTruthy) {
  83         return false;
  84       }
  85diff --git a/src/RawFormulas/Math.ts b/src/RawFormulas/Math.ts
  86index c378311..91e4ca3 100644
  87--- a/src/RawFormulas/Math.ts
  88+++ b/src/RawFormulas/Math.ts
  89@@ -1,16 +1,8 @@
  90 import {
  91-  checkArgumentsLength,
  92-  checkArgumentsAtLeastLength,
  93-  valueToNumber,
  94-  filterOutStringValues,
  95-  flatten,
  96-  filterOutNonNumberValues,
  97-  stringValuesToZeros,
  98-  firstValueAsNumber,
  99-  valueToBoolean,
 100-  checkArgumentsAtWithin,
 101+  ArgsChecker,
 102   CriteriaFunctionFactory,
 103-  valueCanCoerceToNumber
 104+  Filter,
 105+  TypeCaster,
 106 } from "./Utils";
 107 import { CellError } from "../Errors";
 108 import * as ERRORS from "../Errors";
 109@@ -22,8 +14,8 @@ import * as ERRORS from "../Errors";
 110  * @constructor
 111  */
 112 var ABS = function (...values) {
 113-  checkArgumentsLength(values, 1);
 114-  var v = valueToNumber(values[0]);
 115+  ArgsChecker.checkLength(values, 1);
 116+  var v = TypeCaster.valueToNumber(values[0]);
 117   return Math.abs(v);
 118 };
 119 
 120@@ -34,8 +26,8 @@ var ABS = function (...values) {
 121  * @constructor
 122  */
 123 var ACOS = function (value?) {
 124-  checkArgumentsLength(arguments, 1);
 125-  value = valueToNumber(value);
 126+  ArgsChecker.checkLength(arguments, 1);
 127+  value = TypeCaster.valueToNumber(value);
 128   if (value === -1) {
 129     return Math.PI;
 130   } else if (value > 1 || value < -1) {
 131@@ -51,8 +43,8 @@ var ACOS = function (value?) {
 132  * @constructor
 133  */
 134 var ACOSH = function (value?) {
 135-  checkArgumentsLength(arguments, 1);
 136-  value = valueToNumber(value);
 137+  ArgsChecker.checkLength(arguments, 1);
 138+  value = TypeCaster.valueToNumber(value);
 139   if (value < 1) {
 140     throw new CellError(ERRORS.NUM_ERROR, "Function ____ parameter 1 value is " + value + ". It should be greater than or equal to 1.");
 141   }
 142@@ -66,8 +58,8 @@ var ACOSH = function (value?) {
 143  * @constructor
 144  */
 145 var ACOTH = function (value?) {
 146-  checkArgumentsLength(arguments, 1);
 147-  value = valueToNumber(value);
 148+  ArgsChecker.checkLength(arguments, 1);
 149+  value = TypeCaster.valueToNumber(value);
 150   if (value <= 1 && value >= -1) {
 151     throw new CellError(ERRORS.NUM_ERROR, "Function ____ parameter 1 value is " + value + ". Valid values cannot be between -1 and 1 inclusive.")
 152   }
 153@@ -81,7 +73,7 @@ var ACOTH = function (value?) {
 154  * @constructor
 155  */
 156 var ARABIC = function (text?) {
 157-  checkArgumentsLength(arguments, 1);
 158+  ArgsChecker.checkLength(arguments, 1);
 159   if (typeof text !== "string") {
 160     throw new CellError(ERRORS.VALUE_ERROR, 'Invalid roman numeral in ARABIC evaluation.');
 161   }
 162@@ -111,8 +103,8 @@ var ARABIC = function (text?) {
 163  * @constructor
 164  */
 165 var ASIN = function (value?) {
 166-  checkArgumentsLength(arguments, 1);
 167-  value = valueToNumber(value);
 168+  ArgsChecker.checkLength(arguments, 1);
 169+  value = TypeCaster.valueToNumber(value);
 170   if (value === -1) {
 171     return Math.PI;
 172   } else if (value > 1 || value < -1) {
 173@@ -128,8 +120,8 @@ var ASIN = function (value?) {
 174  * @constructor
 175  */
 176 var ASINH = function (value?) {
 177-  checkArgumentsLength(arguments, 1);
 178-  value = valueToNumber(value);
 179+  ArgsChecker.checkLength(arguments, 1);
 180+  value = TypeCaster.valueToNumber(value);
 181   return Math.log(value + Math.sqrt(value * value + 1));
 182 };
 183 
 184@@ -141,8 +133,8 @@ var ASINH = function (value?) {
 185  * @constructor
 186  */
 187 var ATAN = function (value?) {
 188-  checkArgumentsLength(arguments, 1);
 189-  value = valueToNumber(value);
 190+  ArgsChecker.checkLength(arguments, 1);
 191+  value = TypeCaster.valueToNumber(value);
 192   if (value === -1) {
 193     return Math.PI;
 194   } else if (value > 1 || value < -1) {
 195@@ -160,9 +152,9 @@ var ATAN = function (value?) {
 196  * @constructor
 197  */
 198 var ATAN2 = function (x, y) {
 199-  checkArgumentsLength(arguments, 2);
 200-  x = valueToNumber(x);
 201-  y = valueToNumber(y);
 202+  ArgsChecker.checkLength(arguments, 2);
 203+  x = TypeCaster.valueToNumber(x);
 204+  y = TypeCaster.valueToNumber(y);
 205   if (x === 0 && y === 0) {
 206     throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function ATAN2 caused a divide by zero error.");
 207   }
 208@@ -177,8 +169,8 @@ var ATAN2 = function (x, y) {
 209  * @constructor
 210  */
 211 var ATANH = function (value?) : number {
 212-  checkArgumentsLength(arguments, 1);
 213-  value = valueToNumber(value);
 214+  ArgsChecker.checkLength(arguments, 1);
 215+  value = TypeCaster.valueToNumber(value);
 216   if (value >= 1 || value <= -1) {
 217     throw new CellError(ERRORS.NUM_ERROR, "Function ATANH parameter 1 value is " + value + ". Valid values are between -1 and 1 exclusive.");
 218   }
 219@@ -196,7 +188,7 @@ var ATANH = function (value?) : number {
 220  * @constructor
 221  */
 222 var AVERAGE = function (...values) : number {
 223-  checkArgumentsAtLeastLength(values, 1);
 224+  ArgsChecker.checkAtLeastLength(values, 1);
 225   var result = 0;
 226   var count = 0;
 227   for (var i = 0; i < values.length; i++) {
 228@@ -204,11 +196,11 @@ var AVERAGE = function (...values) : number {
 229       if (values[i].length === 0) {
 230         throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
 231       }
 232-      var filtered = filterOutStringValues(values[i]);
 233+      var filtered = Filter.filterOutStringValues(values[i]);
 234       result = result + SUM.apply(this, filtered);
 235       count += filtered.length;
 236     } else {
 237-      result = result + valueToNumber(values[i]);
 238+      result = result + TypeCaster.valueToNumber(values[i]);
 239       count++;
 240     }
 241   }
 242@@ -222,7 +214,7 @@ var AVERAGE = function (...values) : number {
 243  * @constructor
 244  */
 245 var AVEDEV = function (...values) {
 246-  checkArgumentsAtLeastLength(values, 1);
 247+  ArgsChecker.checkAtLeastLength(values, 1);
 248 
 249   // Sort to array-values, and non-array-values
 250   var arrayValues = [];
 251@@ -235,26 +227,26 @@ var AVEDEV = function (...values) {
 252       }
 253       arrayValues.push(X);
 254     } else {
 255-      nonArrayValues.push(valueToNumber(X));
 256+      nonArrayValues.push(TypeCaster.valueToNumber(X));
 257     }
 258   }
 259 
 260   // Remove string values from array-values, but not from non-array-values, and concat.
 261-  var flatValues = filterOutStringValues(flatten(arrayValues)).map(function (value) {
 262-    return valueToNumber(value);
 263+  var flatValues = Filter.filterOutStringValues(Filter.flatten(arrayValues)).map(function (value) {
 264+    return TypeCaster.valueToNumber(value);
 265   }).concat(nonArrayValues);
 266 
 267   // Calculating mean
 268   var result = 0;
 269   var count = 0;
 270   for (var i = 0; i < flatValues.length; i++) {
 271-    result = result + valueToNumber(flatValues[i]);
 272+    result = result + TypeCaster.valueToNumber(flatValues[i]);
 273     count++;
 274   }
 275   var mean = result / count;
 276 
 277   for (var i = 0; i < flatValues.length; i++) {
 278-    flatValues[i] = ABS(valueToNumber(flatValues[i]) - mean);
 279+    flatValues[i] = ABS(TypeCaster.valueToNumber(flatValues[i]) - mean);
 280   }
 281   return SUM(flatValues) / flatValues.length;
 282 };
 283@@ -266,7 +258,7 @@ var AVEDEV = function (...values) {
 284  * @constructor
 285  */
 286 var AVERAGEA = function (...values) {
 287-  checkArgumentsAtLeastLength(values, 1);
 288+  ArgsChecker.checkAtLeastLength(values, 1);
 289   var result = 0;
 290   var count = 0;
 291   for (var i = 0; i < values.length; i++) {
 292@@ -274,11 +266,11 @@ var AVERAGEA = function (...values) {
 293       if (values[i].length === 0) {
 294         throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
 295       }
 296-      var filtered = stringValuesToZeros(values[i]);
 297+      var filtered = Filter.stringValuesToZeros(values[i]);
 298       result = result + SUM.apply(this, filtered);
 299       count += filtered.length;
 300     } else {
 301-      result = result + valueToNumber(values[i]);
 302+      result = result + TypeCaster.valueToNumber(values[i]);
 303       count++;
 304     }
 305   }
 306@@ -292,14 +284,14 @@ var AVERAGEA = function (...values) {
 307  * @constructor
 308  */
 309 var EVEN = function (...values) : number {
 310-  checkArgumentsLength(values, 1);
 311+  ArgsChecker.checkLength(values, 1);
 312   if (values[0] instanceof Array) {
 313     if (values[0].length === 0) {
 314       throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
 315     }
 316     return EVEN(values[0][0]);
 317   }
 318-  var X = valueToNumber(values[0]);
 319+  var X = TypeCaster.valueToNumber(values[0]);
 320   return X % 2 === 1 ? X + 1 : X;
 321 };
 322 
 323@@ -310,19 +302,19 @@ var EVEN = function (...values) : number {
 324  * @constructor
 325  */
 326 var MAX = function (...values) {
 327-  checkArgumentsAtLeastLength(values, 1);
 328+  ArgsChecker.checkAtLeastLength(values, 1);
 329   var maxSoFar = -Infinity;
 330   for (var i = 0; i < values.length; i++) {
 331     if (values[i] instanceof Array) {
 332       if (values[i].length === 0) {
 333         throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
 334       }
 335-      var filtered = filterOutStringValues(values[i]);
 336+      var filtered = Filter.filterOutStringValues(values[i]);
 337       if (filtered.length !== 0) {
 338         maxSoFar = Math.max(MAX.apply(this, filtered), maxSoFar);
 339       }
 340     } else {
 341-      maxSoFar = Math.max(valueToNumber(values[i]), maxSoFar);
 342+      maxSoFar = Math.max(TypeCaster.valueToNumber(values[i]), maxSoFar);
 343     }
 344   }
 345   return maxSoFar;
 346@@ -346,26 +338,26 @@ var MAXA = function (...values) : number {
 347  * @constructor
 348  */
 349 var MEDIAN = function (...values) : number {
 350-  checkArgumentsAtLeastLength(values, 1);
 351+  ArgsChecker.checkAtLeastLength(values, 1);
 352   var sortedArray = [];
 353   values.forEach(function (currentValue) {
 354     if (currentValue instanceof Array) {
 355       if (currentValue.length === 0) {
 356         throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
 357       }
 358-      var filtered = filterOutStringValues(currentValue);
 359+      var filtered = Filter.filterOutStringValues(currentValue);
 360       sortedArray = sortedArray.concat(filtered);
 361     } else {
 362       sortedArray.push(currentValue);
 363     }
 364   });
 365   sortedArray = sortedArray.sort(function (a, b) {
 366-    var aN = valueToNumber(a);
 367-    var bN = valueToNumber(b);
 368+    var aN = TypeCaster.valueToNumber(a);
 369+    var bN = TypeCaster.valueToNumber(b);
 370     return aN - bN;
 371   });
 372   if (sortedArray.length === 1) {
 373-    return valueToNumber(sortedArray[0]);
 374+    return TypeCaster.valueToNumber(sortedArray[0]);
 375   }
 376   if (sortedArray.length === 0) {
 377     throw new CellError(ERRORS.NUM_ERROR, "MEDIAN has no valid input data.");
 378@@ -391,19 +383,19 @@ var MEDIAN = function (...values) : number {
 379  * @constructor
 380  */
 381 var MIN = function (...values) {
 382-  checkArgumentsAtLeastLength(values, 1);
 383+  ArgsChecker.checkAtLeastLength(values, 1);
 384   var minSoFar = Infinity;
 385   for (var i = 0; i < values.length; i++) {
 386     if (values[i] instanceof Array) {
 387       if (values[i].length === 0) {
 388         throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
 389       }
 390-      var filtered = filterOutStringValues(values[i]);
 391+      var filtered = Filter.filterOutStringValues(values[i]);
 392       if (filtered.length !== 0) {
 393         minSoFar = Math.min(MIN.apply(this, filtered), minSoFar);
 394       }
 395     } else {
 396-      minSoFar = Math.min(valueToNumber(values[i]), minSoFar);
 397+      minSoFar = Math.min(TypeCaster.valueToNumber(values[i]), minSoFar);
 398     }
 399   }
 400   return minSoFar;
 401@@ -429,9 +421,9 @@ var MINA = function (...values) : number {
 402  * @constructor
 403  */
 404 var MOD = function (...values) : number {
 405-  checkArgumentsLength(values, 2);
 406-  var oneN = valueToNumber(values[0]);
 407-  var twoN =  valueToNumber(values[1]);
 408+  ArgsChecker.checkLength(values, 2);
 409+  var oneN = TypeCaster.valueToNumber(values[0]);
 410+  var twoN =  TypeCaster.valueToNumber(values[1]);
 411   if (twoN === 0) {
 412     throw new CellError(ERRORS.DIV_ZERO_ERROR, "Function MOD parameter 2 cannot be zero.");
 413   }
 414@@ -446,14 +438,14 @@ var MOD = function (...values) : number {
 415  * @constructor
 416  */
 417 var ODD = function (...values) : number {
 418-  checkArgumentsLength(values, 1);
 419+  ArgsChecker.checkLength(values, 1);
 420   if (values[0] instanceof Array) {
 421     if (values[0].length === 0) {
 422       throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
 423     }
 424     return ODD(values[0][0]);
 425   }
 426-  var X = valueToNumber(values[0]);
 427+  var X = TypeCaster.valueToNumber(values[0]);
 428   return X % 2 === 1 ? X : X + 1;
 429 };
 430 
 431@@ -465,9 +457,9 @@ var ODD = function (...values) : number {
 432  * @constructor
 433  */
 434 var POWER = function (...values) : number {
 435-  checkArgumentsLength(values, 2);
 436-  var n = firstValueAsNumber(values[0]);
 437-  var p = firstValueAsNumber(values[1]);
 438+  ArgsChecker.checkLength(values, 2);
 439+  var n = TypeCaster.firstValueAsNumber(values[0]);
 440+  var p = TypeCaster.firstValueAsNumber(values[1]);
 441   return Math.pow(n, p);
 442 };
 443 
 444@@ -478,7 +470,7 @@ var POWER = function (...values) : number {
 445  * @constructor
 446  */
 447 var SUM = function (...values) : number {
 448-  checkArgumentsAtLeastLength(values, 1);
 449+  ArgsChecker.checkAtLeastLength(values, 1);
 450   var result = 0;
 451   for (var i = 0; i < values.length; i++) {
 452     if (values[i] instanceof Array) {
 453@@ -487,7 +479,7 @@ var SUM = function (...values) : number {
 454       if (values[i] === "") {
 455         throw new CellError(ERRORS.VALUE_ERROR, "Function SUM parameter "+i+" expects number values. But '"+values[i]+"' is a text and cannot be coerced to a number.");
 456       }
 457-      result = result + valueToNumber(values[i]);
 458+      result = result + TypeCaster.valueToNumber(values[i]);
 459     }
 460   }
 461   return result;
 462@@ -500,8 +492,8 @@ var SUM = function (...values) : number {
 463  * @constructor
 464  */
 465 var SQRT = function (...values) : number {
 466-  checkArgumentsLength(values, 1);
 467-  var x = firstValueAsNumber(values[0]);
 468+  ArgsChecker.checkLength(values, 1);
 469+  var x = TypeCaster.firstValueAsNumber(values[0]);
 470   if (x < 0) {
 471     throw new CellError(ERRORS.VALUE_ERROR, "Function SQRT parameter 1 expects number values. But '" + values[0] + "' is a text and cannot be coerced to a number.");
 472   }
 473@@ -515,8 +507,8 @@ var SQRT = function (...values) : number {
 474  * @constructor
 475  */
 476 var COS = function (...values) : number {
 477-  checkArgumentsLength(values, 1);
 478-  var r = firstValueAsNumber(values[0]);
 479+  ArgsChecker.checkLength(values, 1);
 480+  var r = TypeCaster.firstValueAsNumber(values[0]);
 481   return Math.cos(r);
 482 };
 483 
 484@@ -527,8 +519,8 @@ var COS = function (...values) : number {
 485  * @constructor
 486  */
 487 var COSH = function (...values) : number {
 488-  checkArgumentsLength(values, 1);
 489-  var r = firstValueAsNumber(values[0]);
 490+  ArgsChecker.checkLength(values, 1);
 491+  var r = TypeCaster.firstValueAsNumber(values[0]);
 492   return Math["cosh"](r);
 493 };
 494 
 495@@ -539,8 +531,8 @@ var COSH = function (...values) : number {
 496  * @constructor
 497  */
 498 var COT = function (...values) : number {
 499-  checkArgumentsLength(values, 1);
 500-  var x = firstValueAsNumber(values[0]);
 501+  ArgsChecker.checkLength(values, 1);
 502+  var x = TypeCaster.firstValueAsNumber(values[0]);
 503   if (x === 0) {
 504     throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function COT caused a divide by zero error.");
 505   }
 506@@ -554,8 +546,8 @@ var COT = function (...values) : number {
 507  * @constructor
 508  */
 509 var COTH = function (...values) : number {
 510-  checkArgumentsLength(values, 1);
 511-  var x = firstValueAsNumber(values[0]);
 512+  ArgsChecker.checkLength(values, 1);
 513+  var x = TypeCaster.firstValueAsNumber(values[0]);
 514   if (x === 0) {
 515     throw new CellError(ERRORS.DIV_ZERO_ERROR, "Evaluation of function COTH caused a divide by zero error.");
 516   }
 517@@ -569,8 +561,8 @@ var COTH = function (...values) : number {
 518  * @constructor
 519  */
 520 var INT = function (...values) : number {
 521-  checkArgumentsLength(values, 1);
 522-  var x = firstValueAsNumber(values[0]);
 523+  ArgsChecker.checkLength(values, 1);
 524+  var x = TypeCaster.firstValueAsNumber(values[0]);
 525   return Math.floor(x);
 526 };
 527 
 528@@ -582,11 +574,11 @@ var INT = function (...values) : number {
 529  * @constructor
 530  */
 531 var ISEVEN = function (...values) : boolean {
 532-  checkArgumentsLength(values, 1);
 533+  ArgsChecker.checkLength(values, 1);
 534   if (values[0] === "") {
 535     throw new CellError(ERRORS.VALUE_ERROR, "Function ISEVEN parameter 1 expects boolean values. But '" + values[0] + "' is a text and cannot be coerced to a boolean.");
 536   }
 537-  var x = firstValueAsNumber(values[0]);
 538+  var x = TypeCaster.firstValueAsNumber(values[0]);
 539   return Math.floor(x) % 2 === 0;
 540 };
 541 
 542@@ -598,11 +590,11 @@ var ISEVEN = function (...values) : boolean {
 543  * @constructor
 544  */
 545 var ISODD = function (...values) : boolean {
 546-  checkArgumentsLength(values, 1);
 547+  ArgsChecker.checkLength(values, 1);
 548   if (values[0] === "") {
 549     throw new CellError(ERRORS.VALUE_ERROR, "Function ISODD parameter 1 expects boolean values. But '" + values[0] + "' is a text and cannot be coerced to a boolean.");
 550   }
 551-  var x = firstValueAsNumber(values[0]);
 552+  var x = TypeCaster.firstValueAsNumber(values[0]);
 553   return Math.floor(x) % 2 === 1;
 554 };
 555 
 556@@ -613,8 +605,8 @@ var ISODD = function (...values) : boolean {
 557  * @constructor
 558  */
 559 var SIN = function (...values) {
 560-  checkArgumentsLength(values, 1);
 561-  var rad = firstValueAsNumber(values[0]);
 562+  ArgsChecker.checkLength(values, 1);
 563+  var rad = TypeCaster.firstValueAsNumber(values[0]);
 564   return rad === Math.PI ? 0 : Math.sin(rad);
 565 };
 566 
 567@@ -625,8 +617,8 @@ var SIN = function (...values) {
 568  * @constructor
 569  */
 570 var SINH = function (...values) : number {
 571-  checkArgumentsLength(values, 1);
 572-  var rad = firstValueAsNumber(values[0]);
 573+  ArgsChecker.checkLength(values, 1);
 574+  var rad = TypeCaster.firstValueAsNumber(values[0]);
 575   return Math["sinh"](rad);
 576 };
 577 
 578@@ -646,8 +638,8 @@ var PI = function () {
 579  * @constructor
 580  */
 581 var LOG10 = function (...values) : number {
 582-  checkArgumentsLength(values, 1);
 583-  var n = firstValueAsNumber(values[0]);
 584+  ArgsChecker.checkLength(values, 1);
 585+  var n = TypeCaster.firstValueAsNumber(values[0]);
 586   if (n < 1) {
 587     throw new CellError(ERRORS.NUM_ERROR, "Function LOG10 parameter 1 value is " + n + ". It should be greater than 0.");
 588   }
 589@@ -664,11 +656,11 @@ var LOG10 = function (...values) : number {
 590  * @constructor
 591  */
 592 var LOG = function (...values) : number {
 593-  checkArgumentsAtLeastLength(values, 1);
 594-  var n = firstValueAsNumber(values[0]);
 595+  ArgsChecker.checkAtLeastLength(values, 1);
 596+  var n = TypeCaster.firstValueAsNumber(values[0]);
 597   var b = 10;
 598   if (values.length > 1) {
 599-    b = firstValueAsNumber(values[1]);
 600+    b = TypeCaster.firstValueAsNumber(values[1]);
 601     if (b < 1) {
 602       throw new CellError(ERRORS.NUM_ERROR, "Function LOG parameter 2 value is " + b + ". It should be greater than 0.");
 603     }
 604@@ -691,8 +683,8 @@ var LOG = function (...values) : number {
 605  * @constructor
 606  */
 607 var LN = function (...values) : number {
 608-  checkArgumentsLength(values, 1);
 609-  var n = firstValueAsNumber(values[0]);
 610+  ArgsChecker.checkLength(values, 1);
 611+  var n = TypeCaster.firstValueAsNumber(values[0]);
 612   if (n < 1) {
 613     throw new CellError(ERRORS.NUM_ERROR, "Function LN parameter 1 value is " + n + ". It should be greater than 0.");
 614   }
 615@@ -706,8 +698,8 @@ var LN = function (...values) : number {
 616  * @constructor
 617  */
 618 var TAN = function (...values) : number {
 619-  checkArgumentsLength(values, 1);
 620-  var rad = firstValueAsNumber(values[0]);
 621+  ArgsChecker.checkLength(values, 1);
 622+  var rad = TypeCaster.firstValueAsNumber(values[0]);
 623   return rad === Math.PI ? 0 : Math.tan(rad);
 624 };
 625 
 626@@ -718,8 +710,8 @@ var TAN = function (...values) : number {
 627  * @constructor
 628  */
 629 var TANH = function (...values) : number {
 630-  checkArgumentsLength(values, 1);
 631-  var rad = firstValueAsNumber(values[0]);
 632+  ArgsChecker.checkLength(values, 1);
 633+  var rad = TypeCaster.firstValueAsNumber(values[0]);
 634   return Math["tanh"](rad);
 635 };
 636 
 637@@ -735,14 +727,14 @@ var TANH = function (...values) : number {
 638  * TODO: This needs to also accept a third parameter "average_range"
 639  */
 640 var AVERAGEIF = function (...values) {
 641-  checkArgumentsLength(values, 2);
 642+  ArgsChecker.checkLength(values, 2);
 643   var range = values[0];
 644   var criteriaEvaluation = CriteriaFunctionFactory.createCriteriaFunction(values[1]);
 645 
 646   var result = 0;
 647   var count = 0;
 648   for (var i = 0; i < range.length; i++) {
 649-    var val = valueToNumber(range[i]);
 650+    var val = TypeCaster.valueToNumber(range[i]);
 651     if (criteriaEvaluation(val)) {
 652       result = result + val;
 653       count++;
 654@@ -762,12 +754,12 @@ var AVERAGEIF = function (...values) {
 655  * @constructor
 656  */
 657 var CEILING = function (...values) : number {
 658-  checkArgumentsAtWithin(values, 1, 2);
 659-  var num = firstValueAsNumber(values[0]);
 660+  ArgsChecker.checkLengthWithin(values, 1, 2);
 661+  var num = TypeCaster.firstValueAsNumber(values[0]);
 662   if (values.length === 1) {
 663     return Math.ceil(num);
 664   }
 665-  var significance = firstValueAsNumber(values[1]);
 666+  var significance = TypeCaster.firstValueAsNumber(values[1]);
 667   if (significance === 0) {
 668     throw new CellError(ERRORS.DIV_ZERO_ERROR, "Function CEILING parameter 2 cannot be zero.");
 669   }
 670@@ -787,12 +779,12 @@ var CEILING = function (...values) : number {
 671  * @constructor
 672  */
 673 var FLOOR = function (...values) : number {
 674-  checkArgumentsAtWithin(values, 1, 2);
 675-  var num = firstValueAsNumber(values[0]);
 676+  ArgsChecker.checkLengthWithin(values, 1, 2);
 677+  var num = TypeCaster.firstValueAsNumber(values[0]);
 678   if (values.length === 1) {
 679     return Math.floor(num);
 680   }
 681-  var significance = firstValueAsNumber(values[1]);
 682+  var significance = TypeCaster.firstValueAsNumber(values[1]);
 683   if (significance === 0) {
 684     throw new CellError(ERRORS.DIV_ZERO_ERROR, "Function FLOOR parameter 2 cannot be zero.");
 685   }
 686@@ -813,7 +805,7 @@ var FLOOR = function (...values) : number {
 687  * @constructor
 688  */
 689 var IF = function (...values) : any {
 690-  checkArgumentsLength(values, 3);
 691+  ArgsChecker.checkLength(values, 3);
 692   if (values[0] instanceof Array) {
 693     if (values[0].length === 0) {
 694       throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
 695@@ -822,7 +814,7 @@ var IF = function (...values) : any {
 696   } else if (values[0] === "") {
 697     return values[2];
 698   }
 699-  return (valueToBoolean(values[0])) ? values[1] : values[2];
 700+  return (TypeCaster.valueToBoolean(values[0])) ? values[1] : values[2];
 701 };
 702 
 703 /**
 704@@ -832,14 +824,14 @@ var IF = function (...values) : any {
 705  * @constructor
 706  */
 707 var COUNT = function (...values) : number {
 708-  checkArgumentsAtLeastLength(values, 1);
 709+  ArgsChecker.checkAtLeastLength(values, 1);
 710   var count = 0;
 711   for (var i = 0; i < values.length; i++) {
 712     if (values[i] instanceof Array) {
 713       if (values[i].length > 0) {
 714         count += COUNT.apply(this, values[i]);
 715       }
 716-    } else if (valueCanCoerceToNumber(values[i])) {
 717+    } else if (TypeCaster.canCoerceToNumber(values[i])) {
 718       count++;
 719     }
 720   }
 721@@ -858,7 +850,7 @@ var COUNT = function (...values) : number {
 722  * TODO: This needs to take nested range values.
 723  */
 724 var COUNTIF = function (...values) {
 725-  checkArgumentsLength(values, 2);
 726+  ArgsChecker.checkLength(values, 2);
 727   var range = values[0];
 728   var criteria = values[1];
 729 
 730@@ -884,7 +876,7 @@ var COUNTIF = function (...values) {
 731  * TODO: This needs to take nested range values.
 732  */
 733 var COUNTIFS = function (...values) {
 734-  checkArgumentsAtLeastLength(values, 2);
 735+  ArgsChecker.checkAtLeastLength(values, 2);
 736   var criteriaEvaluationFunctions = values.map(function (criteria, index) {
 737     if (index % 2 === 1) {
 738       return CriteriaFunctionFactory.createCriteriaFunction(criteria);
 739@@ -923,7 +915,7 @@ var COUNTIFS = function (...values) {
 740  * @constructor
 741  */
 742 var COUNTA = function (...values) : number {
 743-  checkArgumentsAtLeastLength(values, 1);
 744+  ArgsChecker.checkAtLeastLength(values, 1);
 745   var count = 0;
 746   for (var i = 0; i < values.length; i++) {
 747     if (values[i] instanceof Array) {
 748@@ -947,11 +939,11 @@ var COUNTA = function (...values) : number {
 749  * @constructor
 750  */
 751 var DELTA = function (...values) : number {
 752-  checkArgumentsAtWithin(values, 1, 2);
 753+  ArgsChecker.checkLengthWithin(values, 1, 2);
 754   if (values.length === 1) {
 755-    return valueToNumber(values[0]) === 0 ? 1 : 0;
 756+    return TypeCaster.valueToNumber(values[0]) === 0 ? 1 : 0;
 757   }
 758-  return valueToNumber(values[0]) === valueToNumber(values[1]) ? 1 : 0;
 759+  return TypeCaster.valueToNumber(values[0]) === TypeCaster.valueToNumber(values[1]) ? 1 : 0;
 760 };
 761 
 762 /**
 763@@ -962,12 +954,12 @@ var DELTA = function (...values) : number {
 764  * @constructor
 765  */
 766 var ROUND = function (...values) {
 767-  checkArgumentsAtWithin(values, 1, 2);
 768-  var n = firstValueAsNumber(values[0]);
 769+  ArgsChecker.checkLengthWithin(values, 1, 2);
 770+  var n = TypeCaster.firstValueAsNumber(values[0]);
 771   if (values.length === 1) {
 772     return Math.round(n);
 773   }
 774-  var d = firstValueAsNumber(values[1]);
 775+  var d = TypeCaster.firstValueAsNumber(values[1]);
 776   return Math.round(n * Math.pow(10, d)) / Math.pow(10, d);
 777 };
 778 
 779@@ -979,12 +971,12 @@ var ROUND = function (...values) {
 780  * @constructor
 781  */
 782 var ROUNDDOWN = function (...values) {
 783-  checkArgumentsAtWithin(values, 1, 2);
 784-  var n = firstValueAsNumber(values[0]);
 785+  ArgsChecker.checkLengthWithin(values, 1, 2);
 786+  var n = TypeCaster.firstValueAsNumber(values[0]);
 787   if (values.length === 1) {
 788     return Math.floor(n);
 789   }
 790-  var d = firstValueAsNumber(values[1]);
 791+  var d = TypeCaster.firstValueAsNumber(values[1]);
 792   return Math.floor(n * Math.pow(10, d)) / Math.pow(10, d);
 793 };
 794 
 795@@ -996,12 +988,12 @@ var ROUNDDOWN = function (...values) {
 796  * @constructor
 797  */
 798 var ROUNDUP = function (...values) {
 799-  checkArgumentsAtWithin(values, 1, 2);
 800-  var n = firstValueAsNumber(values[0]);
 801+  ArgsChecker.checkLengthWithin(values, 1, 2);
 802+  var n = TypeCaster.firstValueAsNumber(values[0]);
 803   if (values.length === 1) {
 804     return Math.ceil(n);
 805   }
 806-  var d = firstValueAsNumber(values[1]);
 807+  var d = TypeCaster.firstValueAsNumber(values[1]);
 808   return Math.ceil(n * Math.pow(10, d)) / Math.pow(10, d);
 809 };
 810 
 811@@ -1018,7 +1010,7 @@ var ROUNDUP = function (...values) {
 812  * TODO: This needs to take nested range values.
 813  */
 814 var SUMIF = function (...values) {
 815-  checkArgumentsAtWithin(values, 2, 3);
 816+  ArgsChecker.checkLengthWithin(values, 2, 3);
 817   var range = values[0];
 818   var criteria = values[1];
 819   var sumRange = null;
 820@@ -1034,10 +1026,10 @@ var SUMIF = function (...values) {
 821     if (sumRange && i > sumRange.length-1) {
 822       continue;
 823     }
 824-    if (values.length === 2 && valueCanCoerceToNumber(x) && criteriaEvaluation(x)) {
 825-      sum = sum + x;
 826-    } else if (values.length === 3 && valueCanCoerceToNumber(sumRange[i]) && criteriaEvaluation(x)) {
 827-      sum = sum + sumRange[i];
 828+    if (values.length === 2 && TypeCaster.canCoerceToNumber(x) && criteriaEvaluation(x)) {
 829+      sum = sum + TypeCaster.valueToNumber(x);
 830+    } else if (values.length === 3 && TypeCaster.canCoerceToNumber(sumRange[i]) && criteriaEvaluation(x)) {
 831+      sum = sum + TypeCaster.valueToNumber(sumRange[i]);
 832     }
 833   }
 834   return sum;
 835@@ -1050,16 +1042,16 @@ var SUMIF = function (...values) {
 836  * @constructor
 837  */
 838 var SUMSQ = function (...values) {
 839-  checkArgumentsAtLeastLength(values, 1);
 840+  ArgsChecker.checkAtLeastLength(values, 1);
 841   var result = 0;
 842   for (var i = 0; i < values.length; i++) {
 843     if (values[i] instanceof Array) {
 844       if (values[i].length === 0) {
 845         throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
 846       }
 847-      result = result + SUMSQ.apply(this, filterOutNonNumberValues(values[i]));
 848+      result = result + SUMSQ.apply(this, Filter.filterOutNonNumberValues(values[i]));
 849     } else {
 850-      var n = valueToNumber(values[i]);
 851+      var n = TypeCaster.valueToNumber(values[i]);
 852       result = result + (n * n);
 853     }
 854   }
 855@@ -1079,11 +1071,11 @@ var SUMSQ = function (...values) {
 856  * @constructor
 857  */
 858 var TRUNC = function (...values) : number {
 859-  checkArgumentsAtWithin(values, 1, 2);
 860-  var n = firstValueAsNumber(values[0]);
 861+  ArgsChecker.checkLengthWithin(values, 1, 2);
 862+  var n = TypeCaster.firstValueAsNumber(values[0]);
 863   var digits = 0;
 864   if (values.length === 2) {
 865-    digits = firstValueAsNumber(values[1]);
 866+    digits = TypeCaster.firstValueAsNumber(values[1]);
 867   }
 868   var sign = (n > 0) ? 1 : -1;
 869   return sign * (Math.floor(Math.abs(n) * Math.pow(10, digits))) / Math.pow(10, digits);
 870diff --git a/src/RawFormulas/Misc.ts b/src/RawFormulas/Misc.ts
 871index adfefdd..3bbe308 100644
 872--- a/src/RawFormulas/Misc.ts
 873+++ b/src/RawFormulas/Misc.ts
 874@@ -1,11 +1,6 @@
 875 import {
 876-  valueToString,
 877-  firstValueAsNumber,
 878-  firstValueAsString,
 879-  firstValueAsBoolean,
 880-  checkArgumentsLength,
 881-  checkArgumentsAtWithin,
 882-  checkArgumentsAtLeastLength
 883+  ArgsChecker,
 884+  TypeCaster
 885 } from "./Utils";
 886 import { CellError } from "../Errors"
 887 import * as ERRORS from "../Errors"
 888@@ -17,8 +12,8 @@ import * as ERRORS from "../Errors"
 889  * @constructor
 890  */
 891 var CHAR = function (...values) : string {
 892-  checkArgumentsLength(values, 1);
 893-  var n = firstValueAsNumber(values[0]);
 894+  ArgsChecker.checkLength(values, 1);
 895+  var n = TypeCaster.firstValueAsNumber(values[0]);
 896   if (n < 1 || n > 1114112) { //limit
 897     throw new CellError(ERRORS.NUM_ERROR, "Function CHAR parameter 1 value " + n + " is out of range.");
 898   }
 899@@ -32,8 +27,8 @@ var CHAR = function (...values) : string {
 900  * @constructor
 901  */
 902 var CODE = function (...values) : number {
 903-  checkArgumentsLength(values, 1);
 904-  var text = firstValueAsString(values[0]);
 905+  ArgsChecker.checkLength(values, 1);
 906+  var text = TypeCaster.firstValueAsString(values[0]);
 907   if (text === "") {
 908     throw new CellError(ERRORS.VALUE_ERROR, "Function CODE parameter 1 value should be non-empty.");
 909   }
 910@@ -51,12 +46,12 @@ var CODE = function (...values) : number {
 911  * TODO: At some point this needs to return a more complex type than Array. Needs to return a type that has a dimension.
 912  */
 913 var SPLIT = function (...values) : Array<string> {
 914-  checkArgumentsAtWithin(values, 2, 3);
 915-  var text = firstValueAsString(values[0]);
 916-  var delimiter = firstValueAsString(values[1]);
 917+  ArgsChecker.checkLengthWithin(values, 2, 3);
 918+  var text = TypeCaster.firstValueAsString(values[0]);
 919+  var delimiter = TypeCaster.firstValueAsString(values[1]);
 920   var splitByEach = false;
 921   if (values.length === 3) {
 922-    splitByEach = firstValueAsBoolean(values[2]);
 923+    splitByEach = TypeCaster.firstValueAsBoolean(values[2]);
 924   }
 925   if (splitByEach) {
 926     var result = [text];
 927@@ -83,7 +78,7 @@ var SPLIT = function (...values) : Array<string> {
 928  * @constructor
 929  */
 930 var CONCATENATE = function (...values) : string {
 931-  checkArgumentsAtLeastLength(values, 1);
 932+  ArgsChecker.checkAtLeastLength(values, 1);
 933   var string = '';
 934   for (var i = 0; i < values.length; i++) {
 935     if (values[i] instanceof Array) {
 936@@ -92,7 +87,7 @@ var CONCATENATE = function (...values) : string {
 937       }
 938       string += CONCATENATE.apply(this, arguments[i]);
 939     } else {
 940-      string += valueToString(values[i]);
 941+      string += TypeCaster.valueToString(values[i]);
 942     }
 943   }
 944   return string;
 945diff --git a/src/RawFormulas/RawFormulas.ts b/src/RawFormulas/RawFormulas.ts
 946index 8b79422..676ab5b 100644
 947--- a/src/RawFormulas/RawFormulas.ts
 948+++ b/src/RawFormulas/RawFormulas.ts
 949@@ -73,19 +73,10 @@ import {
 950   CONCATENATE
 951 } from "./Misc";
 952 import {
 953-  checkArgumentsAtLeastLength,
 954-  checkArgumentsAtWithin,
 955-  valueCanCoerceToNumber,
 956-  firstValueAsBoolean,
 957-  filterOutStringValues,
 958   CriteriaFunctionFactory,
 959-  valueToNumber,
 960-  checkArgumentsLength,
 961-  filterOutNonNumberValues,
 962-  firstValueAsNumber,
 963-  firstValueAsString,
 964-  valueToBoolean,
 965-  valueToString
 966+  ArgsChecker,
 967+  Filter,
 968+  TypeCaster
 969 } from "./Utils";
 970 import { CellError } from "../Errors"
 971 import * as ERRORS from "../Errors"
 972diff --git a/src/RawFormulas/Utils.ts b/src/RawFormulas/Utils.ts
 973index f15cbc6..7042ea5 100644
 974--- a/src/RawFormulas/Utils.ts
 975+++ b/src/RawFormulas/Utils.ts
 976@@ -1,221 +1,6 @@
 977 import { CellError } from "../Errors"
 978 import * as ERRORS from "../Errors"
 979 
 980-/**
 981- * Checks to see if the arguments are of the correct length.
 982- * @param args to check length of
 983- * @param length expected length
 984- */
 985-function checkArgumentsLength(args: any, length: number) {
 986-  if (args.length !== length) {
 987-    throw new CellError(ERRORS.NA_ERROR, "Wrong number of arguments to ___. Expected 1 arguments, but got " + args.length + " arguments.");
 988-  }
 989-}
 990-
 991-/**
 992- * Checks to see if the arguments are at least a certain length.
 993- * @param args to check length of
 994- * @param length expected length
 995- */
 996-function checkArgumentsAtLeastLength(args: any, length: number) {
 997-  if (args.length < length) {
 998-    throw new CellError(ERRORS.NA_ERROR, "Wrong number of arguments to ___. Expected 1 arguments, but got " + args.length + " arguments.");
 999-  }
1000-}
1001-
1002-/**
1003- * Checks to see if the arguments are within a max and min, inclusively
1004- * @param args to check length of
1005- * @param low least number of arguments
1006- * @param high max number of arguments
1007- */
1008-function checkArgumentsAtWithin(args: any, low: number, high: number) {
1009-  if (args.length > high || args.length < low) {
1010-    throw new CellError(ERRORS.NA_ERROR, "Wrong number of arguments to ___. Expected 1 arguments, but got " + args.length + " arguments.");
1011-  }
1012-}
1013-
1014-/**
1015- * Filter out all strings from an array.
1016- * @param arr to filter
1017- * @returns {Array} filtered array
1018- */
1019-function filterOutStringValues(arr: Array<any>) : Array<any> {
1020-  var toReturn = [];
1021-  for (var i = 0; i < arr.length; i++) {
1022-    if (typeof arr[i] !== "string") {
1023-      toReturn.push(arr[i]);
1024-    }
1025-  }
1026-  return toReturn;
1027-}
1028-
1029-function filterOutNonNumberValues(arr: Array<any>) : Array<any> {
1030-  var toReturn = [];
1031-  for (var i = 0; i < arr.length; i++) {
1032-    if (typeof arr[i] !== "string" && typeof arr[i] !== "boolean") {
1033-      toReturn.push(arr[i]);
1034-    }
1035-  }
1036-  return toReturn;
1037-}
1038-
1039-/**
1040- * Convert a value to string.
1041- * @param value of any type, including array. array cannot be empty.
1042- * @returns {string} string representation of value
1043- */
1044-function valueToString(value: any) : string {
1045-  if (typeof value === "number") {
1046-    return value.toString();
1047-  } else if (typeof value === "string") {
1048-    return value;
1049-  } else if (typeof value === "boolean") {
1050-    return value ? "TRUE" : "FALSE";
1051-  } else if (value instanceof Array) {
1052-    return valueToString(value[0]); // TODO: Take this out. It's stupid. We should handle arrays at a different level.
1053-  }
1054-}
1055-
1056-/**
1057- * Takes any input type and will throw a REF_ERROR or coerce it into a number.
1058- * @param input to attempt to coerce into a number
1059- * @returns {number} number representation of the input
1060- */
1061-function firstValueAsNumber(input: any) : number {
1062-  if (input instanceof Array) {
1063-    if (input.length === 0) {
1064-      throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
1065-    }
1066-    return firstValueAsNumber(input[0]);
1067-  }
1068-  return valueToNumber(input);
1069-}
1070-
1071-/**
1072- * Takes any input type and will throw a REF_ERROR or coerce it into a string.
1073- * @param input to attempt to coerce into a string
1074- * @returns {number} number representation of the input
1075- */
1076-function firstValueAsString(input: any) : string {
1077-  if (input instanceof Array) {
1078-    if (input.length === 0) {
1079-      throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
1080-    }
1081-    return firstValueAsString(input[0]);
1082-  }
1083-  return valueToString(input);
1084-}
1085-
1086-/**
1087- * Takes any input type and will throw a REF_ERROR or coerce it into a string.
1088- * @param input to attempt to coerce into a string
1089- * @returns {number} number representation of the input
1090- */
1091-function firstValueAsBoolean(input: any) : boolean {
1092-  if (input instanceof Array) {
1093-    if (input.length === 0) {
1094-      throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
1095-    }
1096-    return firstValueAsBoolean(input[0]);
1097-  }
1098-  return valueToBoolean(input);
1099-}
1100-
1101-/**
1102- * Converts any value to a number or throws an error if it cannot coerce it to the number type
1103- * @param value to convert
1104- * @returns {number} to return. Will always return a number or throw an error. Never returns undefined.
1105- */
1106-function valueToNumber(value: any) : number {
1107-  if (typeof value === "number") {
1108-    return value;
1109-  } else if (typeof value === "string") {
1110-    if (value === "") {
1111-      return 0;
1112-    }
1113-    if (value.indexOf(".") > -1) {
1114-      var fl = parseFloat(value);
1115-      if (isNaN(fl)) {
1116-        throw new CellError(ERRORS.VALUE_ERROR, "Function ____ expects number values, but is text and cannot be coerced to a number.");
1117-      }
1118-      return fl;
1119-    }
1120-    var fl = parseInt(value);
1121-    if (isNaN(fl)) {
1122-      throw new CellError(ERRORS.VALUE_ERROR, "Function ____ expects number values, but is text and cannot be coerced to a number.");
1123-    }
1124-    return fl;
1125-  } else if (typeof value === "boolean") {
1126-    return value ? 1 : 0;
1127-  }
1128-  return 0;
1129-}
1130-
1131-/**
1132- * Returns true if we can coerce it to the number type
1133- * @param value to coerce
1134- * @returns {boolean} if could be coerced to a number
1135- */
1136-function valueCanCoerceToNumber(value: any) : boolean {
1137-  if (typeof value === "number" || typeof value === "boolean") {
1138-    return true;
1139-  } else if (typeof value === "string") {
1140-    if (value === "") {
1141-      return false;
1142-    }
1143-    if (value.indexOf(".") > -1) {
1144-      return !isNaN(parseFloat(value));
1145-    }
1146-    return !isNaN(parseInt(value));
1147-  }
1148-  return false;
1149-}
1150-
1151-
1152-/**
1153- * Converts string values in array to 0
1154- * @param arr to convert
1155- * @returns {Array} array in which all string values have been converted to 0.
1156- */
1157-function stringValuesToZeros(arr: Array<any>) : Array<any> {
1158-  var toReturn = [];
1159-  for (var i = 0; i < arr.length; i++) {
1160-    if (typeof arr[i] !== "string") {
1161-      toReturn.push(arr[i]);
1162-    } else {
1163-      toReturn.push(0);
1164-    }
1165-  }
1166-  return toReturn;
1167-}
1168-
1169-/**
1170- * Converts any value to a boolean or throws an error if it cannot coerce it to the boolean type.
1171- * @param value to convert
1172- * @returns {boolean} to return.
1173- */
1174-function valueToBoolean(value: any) : boolean {
1175-  if (typeof value === "number") {
1176-    return value !== 0;
1177-  } else if (typeof value === "string") {
1178-    throw new CellError(ERRORS.VALUE_ERROR, "___ expects boolean values. But '" + value + "' is a text and cannot be coerced to a boolean.")
1179-  } else if (typeof value === "boolean") {
1180-    return value;
1181-  }
1182-}
1183-
1184-/**
1185- * Flatten an array of arrays of ...
1186- * @param values array of values
1187- * @returns {Array} flattened array
1188- */
1189-function flatten(values: Array<any>) : Array<any> {
1190-  return values.reduce(function (flat, toFlatten) {
1191-    return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
1192-  }, []);
1193-}
1194-
1195 /**
1196  * Converts wild-card style expressions (in which * matches zero or more characters, and ? matches exactly one character)
1197  * to regular expressions. * and ? can be escaped by prefixing ~
1198@@ -298,21 +83,242 @@ class CriteriaFunctionFactory {
1199   }
1200 }
1201 
1202+/**
1203+ * Static class of helpers used to cast various types to each other.
1204+ */
1205+class TypeCaster {
1206+  /**
1207+   * Converts any value to a number or throws an error if it cannot coerce it to the number type
1208+   * @param value to convert
1209+   * @returns {number} to return. Will always return a number or throw an error. Never returns undefined.
1210+   */
1211+  static valueToNumber(value : any) {
1212+    if (typeof value === "number") {
1213+      return value;
1214+    } else if (typeof value === "string") {
1215+      if (value === "") {
1216+        return 0;
1217+      }
1218+      if (value.indexOf(".") > -1) {
1219+        var fl = parseFloat(value);
1220+        if (isNaN(fl)) {
1221+          throw new CellError(ERRORS.VALUE_ERROR, "Function ____ expects number values, but is text and cannot be coerced to a number.");
1222+        }
1223+        return fl;
1224+      }
1225+      var fl = parseInt(value);
1226+      if (isNaN(fl)) {
1227+        throw new CellError(ERRORS.VALUE_ERROR, "Function ____ expects number values, but is text and cannot be coerced to a number.");
1228+      }
1229+      return fl;
1230+    } else if (typeof value === "boolean") {
1231+      return value ? 1 : 0;
1232+    }
1233+    return 0;
1234+  }
1235+  /**
1236+   * Converts any value to a boolean or throws an error if it cannot coerce it to the boolean type.
1237+   * @param value to convert
1238+   * @returns {boolean} to return.
1239+   */
1240+  static valueToBoolean(value: any) {
1241+    if (typeof value === "number") {
1242+      return value !== 0;
1243+    } else if (typeof value === "string") {
1244+      throw new CellError(ERRORS.VALUE_ERROR, "___ expects boolean values. But '" + value + "' is a text and cannot be coerced to a boolean.")
1245+    } else if (typeof value === "boolean") {
1246+      return value;
1247+    }
1248+  }
1249+  /**
1250+   * Convert a value to string.
1251+   * @param value of any type, including array. array cannot be empty.
1252+   * @returns {string} string representation of value
1253+   */
1254+  static valueToString(value: any) : string {
1255+    if (typeof value === "number") {
1256+      return value.toString();
1257+    } else if (typeof value === "string") {
1258+      return value;
1259+    } else if (typeof value === "boolean") {
1260+      return value ? "TRUE" : "FALSE";
1261+    } else if (value instanceof Array) {
1262+      return this.valueToString(value[0]); // TODO: Take this out. It's stupid. We should handle arrays at a different level.
1263+    }
1264+  }
1265+
1266+  /**
1267+   * Returns true if we can coerce it to the number type.
1268+   * @param value to coerce
1269+   * @returns {boolean} if could be coerced to a number
1270+   */
1271+  static canCoerceToNumber(value: any) : boolean {
1272+    if (typeof value === "number" || typeof value === "boolean") {
1273+      return true;
1274+    } else if (typeof value === "string") {
1275+      if (value === "") {
1276+        return false;
1277+      }
1278+      if (value.indexOf(".") > -1) {
1279+        return !isNaN(parseFloat(value));
1280+      }
1281+      return !isNaN(parseInt(value));
1282+    }
1283+    return false;
1284+  }
1285+
1286+  /**
1287+   * Takes any input type and will throw a REF_ERROR or coerce it into a number.
1288+   * @param input to attempt to coerce into a number
1289+   * @returns {number} number representation of the input
1290+   */
1291+  static firstValueAsNumber(input: any) : number {
1292+    if (input instanceof Array) {
1293+      if (input.length === 0) {
1294+        throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
1295+      }
1296+      return TypeCaster.firstValueAsNumber(input[0]);
1297+    }
1298+    return TypeCaster.valueToNumber(input);
1299+  }
1300+
1301+  /**
1302+   * Takes any input type and will throw a REF_ERROR or coerce it into a string.
1303+   * @param input to attempt to coerce into a string
1304+   * @returns {number} number representation of the input
1305+   */
1306+  static firstValueAsString(input: any) : string {
1307+    if (input instanceof Array) {
1308+      if (input.length === 0) {
1309+        throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
1310+      }
1311+      return TypeCaster.firstValueAsString(input[0]);
1312+    }
1313+    return TypeCaster.valueToString(input);
1314+  }
1315+
1316+  /**
1317+   * Takes any input type and will throw a REF_ERROR or coerce it into a string.
1318+   * @param input to attempt to coerce into a string
1319+   * @returns {number} number representation of the input
1320+   */
1321+  static firstValueAsBoolean(input: any): boolean {
1322+    if (input instanceof Array) {
1323+      if (input.length === 0) {
1324+        throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
1325+      }
1326+      return TypeCaster.firstValueAsBoolean(input[0]);
1327+    }
1328+    return TypeCaster.valueToBoolean(input);
1329+  }
1330+}
1331+
1332+/**
1333+ * Static class to help filter down Arrays
1334+ */
1335+class Filter {
1336+  /**
1337+   * Converts string values in array to 0
1338+   * @param arr to convert
1339+   * @returns {Array} array in which all string values have been converted to 0.
1340+   */
1341+  static stringValuesToZeros(arr: Array<any>) : Array<any> {
1342+    var toReturn = [];
1343+    for (var i = 0; i < arr.length; i++) {
1344+      if (typeof arr[i] !== "string") {
1345+        toReturn.push(arr[i]);
1346+      } else {
1347+        toReturn.push(0);
1348+      }
1349+    }
1350+    return toReturn;
1351+  }
1352+
1353+  /**
1354+   * Flatten an array of arrays of ...
1355+   * @param values array of values
1356+   * @returns {Array} flattened array
1357+   */
1358+  static flatten(values: Array<any>) : Array<any> {
1359+    return values.reduce(function (flat, toFlatten) {
1360+      return flat.concat(Array.isArray(toFlatten) ? Filter.flatten(toFlatten) : toFlatten);
1361+    }, []);
1362+  }
1363+
1364+  /**
1365+   * Filter out all strings from an array.
1366+   * @param arr to filter
1367+   * @returns {Array} filtered array
1368+   */
1369+  static filterOutStringValues(arr: Array<any>) : Array<any> {
1370+    var toReturn = [];
1371+    for (var i = 0; i < arr.length; i++) {
1372+      if (typeof arr[i] !== "string") {
1373+        toReturn.push(arr[i]);
1374+      }
1375+    }
1376+    return toReturn;
1377+  }
1378+
1379+  /**
1380+   * Filters out non number values.
1381+   * @param arr to filter
1382+   * @returns {Array} filtered array
1383+   */
1384+  static filterOutNonNumberValues(arr: Array<any>) : Array<any> {
1385+    var toReturn = [];
1386+    for (var i = 0; i < arr.length; i++) {
1387+      if (typeof arr[i] !== "string" && typeof arr[i] !== "boolean") {
1388+        toReturn.push(arr[i]);
1389+      }
1390+    }
1391+    return toReturn;
1392+  }
1393+}
1394+
1395+/**
1396+ * Static class to check argument length within expected ranges when calling functions.
1397+ */
1398+class ArgsChecker {
1399+  /**
1400+   * Checks to see if the arguments are of the correct length.
1401+   * @param args to check length of
1402+   * @param length expected length
1403+   */
1404+  static checkLength(args: any, length: number) {
1405+    if (args.length !== length) {
1406+      throw new CellError(ERRORS.NA_ERROR, "Wrong number of arguments to ___. Expected 1 arguments, but got " + args.length + " arguments.");
1407+    }
1408+  }
1409+
1410+  /**
1411+   * Checks to see if the arguments are at least a certain length.
1412+   * @param args to check length of
1413+   * @param length expected length
1414+   */
1415+  static checkAtLeastLength(args: any, length: number) {
1416+    if (args.length < length) {
1417+      throw new CellError(ERRORS.NA_ERROR, "Wrong number of arguments to ___. Expected 1 arguments, but got " + args.length + " arguments.");
1418+    }
1419+  }
1420+
1421+  /**
1422+   * Checks to see if the arguments are within a max and min, inclusively
1423+   * @param args to check length of
1424+   * @param low least number of arguments
1425+   * @param high max number of arguments
1426+   */
1427+  static checkLengthWithin(args: any, low: number, high: number) {
1428+    if (args.length > high || args.length < low) {
1429+      throw new CellError(ERRORS.NA_ERROR, "Wrong number of arguments to ___. Expected 1 arguments, but got " + args.length + " arguments.");
1430+    }
1431+  }
1432+  }
1433+
1434 
1435 export {
1436-  stringValuesToZeros,
1437-  firstValueAsBoolean,
1438-  filterOutNonNumberValues,
1439-  flatten,
1440-  valueCanCoerceToNumber,
1441-  valueToNumber,
1442-  valueToString,
1443-  valueToBoolean,
1444-  firstValueAsNumber,
1445-  firstValueAsString,
1446-  filterOutStringValues,
1447-  checkArgumentsAtLeastLength,
1448-  checkArgumentsAtWithin,
1449-  checkArgumentsLength,
1450-  CriteriaFunctionFactory
1451+  ArgsChecker,
1452+  CriteriaFunctionFactory,
1453+  Filter,
1454+  TypeCaster
1455 }
1456\ No newline at end of file
1457diff --git a/tests/FormulasTest.ts b/tests/FormulasTest.ts
1458index dec3d88..7711933 100644
1459--- a/tests/FormulasTest.ts
1460+++ b/tests/FormulasTest.ts
1461@@ -10,7 +10,6 @@ import { ABS, ACCRINT, ACOS, ACOSH, ACOTH, AND, ARABIC, ASIN, ASINH, ATAN, ATAN2
1462     SUMSQ, SUMX2MY2, SUMX2PY2, TAN, TANH, TRUNC, XOR, YEARFRAC } from "../src/RawFormulas/RawFormulas"
1463 import * as ERRORS from "../src/Errors"
1464 import {assertEquals, assertEqualsDates, assertArrayEquals} from "./utils/Asserts"
1465-import {firstValueAsNumber} from "../src/RawFormulas/Utils";
1466 
1467 function catchAndAssertEquals(toExecute, expected) {
1468   var toThrow = null;