Skip to content

Instantly share code, notes, and snippets.

@isocroft
Last active January 25, 2021 21:35
Show Gist options
  • Save isocroft/83777b0a04a0bc94069b0ca9fd24e92e to your computer and use it in GitHub Desktop.
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
/**
* 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
}
@isocroft
Copy link
Author

isocroft commented May 19, 2020

examples:

strictTypeOf([], 'array'); // true
strictTypeOf({}, 'object'); // true
strictTypeOf(null, 'null'); // true
strictTypeOf(window.localStorage, Storage); // true
strictTypeOf('hello!', 'boolean'); // false
strictTypeOf(new URL('/', window.location), 'url'); // true
strictTypeOf(0x35, ['number', 'string']); // true
strictTypeOf("200,000", ['number', 'string']); // true

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment