Last active
January 25, 2021 21:35
-
-
Save isocroft/83777b0a04a0bc94069b0ca9fd24e92e to your computer and use it in GitHub Desktop.
This JavaScript file implements a function that returns the actual type of a JS variable: literal or primitive
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* check if a literal is falsy or not | |
*/ | |
const isLiteralFalsey = (variable) => { | |
return variable === '' || variable === false || variable === 0 | |
} | |
/** | |
* check if a variable contains a reference type (not a literal) | |
*/ | |
const isPrimitive = (arg) => { | |
return typeof arg === 'object' || (Boolean(arg) && typeof arg === 'function') | |
} | |
/** | |
* retrieve the name of a types' constructor or up the prototype chain | |
*/ | |
const getNameByChain = (_type, depth) => { | |
if(typeof depth !== 'number'){ | |
depth = 1; | |
} | |
let name = _type.name || _type.displayName | |
const chainList = [(_type.__proto__ && _type.__proto__.prototype)]; | |
while(Boolean(chainList[0]) | |
&& depth !== 0){ | |
const variable = chainList[0].constructor; | |
if(typeof variable !== 'function'){ | |
break; | |
} | |
name = variable.name || variable.displayName | |
--depth | |
chainList.unshift((variable.__proto__ && variable.__proto__.prototype)); | |
} | |
chainList.length = 0 | |
return name | |
} | |
/** | |
* provide the name of primitive and/or reference types | |
*/ | |
const checkTypeName = (target, type) => { | |
let typeName = '' | |
let match = false | |
let depth = 0 | |
const MAX_DEPTH = 3 | |
if(typeof type === 'function'){ | |
type = (getNameByChain(type, depth)).toLowerCase() | |
} | |
if (isLiteralFalsey(target) || !isPrimitive(target)) { | |
typeName = typeof target | |
} else { | |
typeName = (Object.prototype.toString.call(target)).replace(/^\[object (.+)\]$/, '$1') | |
} | |
match = Boolean(typeName.toLowerCase().indexOf(type) + 1) | |
while(!match){ | |
++depth; | |
if(depth === MAX_DEPTH){ | |
break; | |
} | |
typeName = '' + (target && getNameByChain(target.constructor, depth)) | |
match = Boolean(typeName.toLowerCase().indexOf(type) + 1) | |
} | |
return match; | |
} | |
/** | |
* get the actual type of a variable | |
*/ | |
const strictTypeOf = (value, type) => { | |
let result = false | |
type = type || [] | |
if (typeof type === 'object') { | |
if (typeof type.length !== 'number') { | |
return result | |
} | |
let bitPiece = 0 | |
type = [].slice.call(type) | |
type.forEach(_type => { | |
var localResult = false; | |
if (typeof _type === 'function') { | |
localResult = value instanceof _type | |
} | |
bitPiece |= Number(localResult || checkTypeName(value, _type)) | |
}) | |
result = Boolean(bitPiece) | |
} else { | |
if (typeof type === 'function') { | |
result = value instanceof type | |
} | |
result = result || checkTypeName(value, type) | |
} | |
return result | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
examples: