Dynamic type checking

Hey guys,
I’ve been playing with dynamic type checking for functions.

I figured out how to add a method to Function.prototype that type checks an argument value and short circuits the main function call if undefined or not the correct type.

It then returns an empty value of that type (so it wont return undefined index in looping array)

If it is correct it calls return this(x)
e.g.
makeUpperCase.type('string' , 12) // short circuits function returns ’ ’
makeUpperCase.type('string', 'hello') // calls makeUpperCase('hello') returns ‘HELLO’

The full code is below, can anyone think of any edge cases where this might fall over?

Thanks for your help :slightly_smiling_face:

const arr = ['jim',false,'bill','dave', 123];

let str = 'hotel california'

var toUpper = x => x.toUpperCase();

Function.prototype.type = function(type,x){
  if(!x || typeof x !== type){
    switch(type){
      case 'string': return ''; break;
      case 'number': return 0 ; break;
      case 'boolean': return false; break;
      default: return false;
    }
  }
  return this(x)
}

toUpper.type('string', str);
//'HOTEL CALIFORNIA'

toUpper.type('number', str); 
// returns 0 

toUpper.type('boolean',str)
// returns false

//mutates arr returns last value
for(i = 0; i < arr.length; i++){
arr[i] = toUpper.type('string', arr[i])}
// [ 'JIM', '', 'BILL', 'DAVE', '' ]

//mutates arr returns last value
for(let i of arr){toUpper.type('string', i)}
//[ 'JIM', '', 'BILL', 'DAVE', '' ]

// maps arr returns new arr
arr.map(x => toUpper.type('string',x))
//[ 'JIM', '', 'BILL', 'DAVE', '' ]
console.log(arr)

BTW forEach doesn’t work on this…

One problem is that falsy versions of your types don’t run through the function

console.log.type('string', '') // does not log ''

Numbers have a few falsy values too: 0, -0, and NaN which would also apply here, each resulting in a return value of 0.

You’re also missing a few primitive types in the list that you’re handling now. Missing include: symbols, bigint, and technically null and undefined though despite being their own primitive types, I’m not sure if you’d want them included. typeof can also identify function types as well.

And what if you wanted to pass more than one argument to the function? Right now it only supports 1.

I think it would also be nice to be able to specify the value that’s returned rather than it defaulting to ‘’, 0 or false.

Finally, what happens when the JavaScript language specification introduces a new function method called type and your code runs and replaces it with this version? :scream_cat:

:slight_smile:

1 Like

Thanks again for your help. :slightly_smiling_face:

I thought I’d put the final version up in case anyone has any use for this.

The method now takes multiple arguments, multiple types, a return type and user defined error handling.

It has the following structure someFunc.T(inputType, returnType, errorHandling, ...arguments)

If any argument does not match its type the function will not run and the method will return a value the user specifies.

If the function return type does not match it will default return whatever the user specifies.

The firstinputType argument will take either a single 'type' or array ['type1', 'type2'] of types that Must specify each type for each argument.
If there are multiple arguments and only one inputType argument all arguments will be checked against a single type.

The second argument returnType will assess after the main function has run.

The third argument errorHandling accepts either:
'empty' - will return a blank value of the return type e.g.
[null,2,3,4,Nan].map() -> returns [0,2,3,4,0] (can be used like a maybe or either monad)

'pass' - will just short circuit the function and let the argument pass through e.g. [null,2,3,4,Nan].map() -> returns [null,2,3,4,Nan]

'throw' - will return a throw new error with the function name

a function - will call a user defined function e.g. console.log('whatever')

Any value- passed in by the user. e.g. ‘WTF is happening!’

Function.prototype.T = function(argType,returnType,onError,...args){

if(Array.isArray(argType)){
  if(argType.length !== args.length) return throw new Error('arg array.length invalid');
  for(let[k,i] of args.entries()){
      if(typeof i !== argType[k] || typeof i === 'number' && isNaN(i)) return handle(onError, i) }}
  
else{ for(let i of args){ if(typeof i !== argType || typeof i === 'number' && isNan(i)) return handle(onError, i) }} 
  
 function handle(onError, passValue){
    if(typeof onError === 'function') onError.call();
    if(onError === 'empty' || typeof onError === 'function'){ 
        switch(returnType){
        case 'string': return ''; break;
        case 'number': return 0 ; break;
        case 'object': return {}; break;
        case 'boolean': return false; break;
        case 'bigint' : return 0; break;
        case 'function': return function(){return}; break;   
        case 'symbol' : return new Symbol(); break; 
        default: return;
        }
      } 
    if(onError === 'throw') return throw new Error(`${this.name} Function - argument type             !== argument`);
    if(onError === 'pass') return passValue;
    return onError;
  }
  let val = this(...args);
  if(typeof val !== returnType) return handle(onError, val);
  return val;  
}

If you can see any problems let me know please :slightly_smiling_face: