💾typeName()
JS ⟩ value ⟩ type ⟩ name ⟩ typeName()
printPrototypeChain() - print the prototype chain of an object.
replit:typeName() (v.2)
typeof base type expr value
--------------------------------------------------------------------------
object⭐️ Null Null null null
--------------------------------------------------------------------------
undefined Undefined Undefined undefined undefined
--------------------------------------------------------------------------
number Number Number 37 37
number Number Number 3.14 3.14
number Number Number Math.LN2 0.6931471805599453
number Number Number Infinity Infinity
number Number Number NaN NaN
number Number Number Number('1') 1
number Number Number Number('ab') NaN
--------------------------------------------------------------------------
bigint BigInt BigInt 42 42n
--------------------------------------------------------------------------
string String String 'bla' bla
string String String `x = ${1+2}` x = 3
string String String typeof 1 number
string String String String({}) [object Object]
string String String typeof xxx undefined
--------------------------------------------------------------------------
boolean Boolean Boolean true true
boolean Boolean Boolean Boolean(1) true
boolean Boolean Boolean !!(1) true
--------------------------------------------------------------------------
symbol Symbol Symbol Symbol() Symbol()
symbol Symbol Symbol Symbol.iterator Symbol(Symbol.iterator)
--------------------------------------------------------------------------
object Object Object {a:1} { a: 1 }
object⭐️ User User user User { name: 'JohnDoe' }
object⭐️ Array Array [1, 2] [ 1, 2 ]
object⭐️ Date Date new Date() 2022-09-13T01:26:32.214Z
object⭐️ RegExp RegExp /regex/ /regex/
--------------------------------------------------------------------------
function Function Function function(){} [Function (anonymous)]
function Function Function Math.sin [Function: sin]
function Function Function () => {} [Function (anonymous)]
function⭐️❗ Function class class {} [class (anonymous)]
function⭐️❗ Function class User [class User]
function⭐️ GeneratorFunction GeneratorFunction function*(){} [GeneratorFunction (anonymous)]
--------------------------------------------------------------------------
• ⭐️ types not all the same • ❗ base !== type
replit:typeName() (v.2)
require: isClass(), baseTypeName()
// ⭐️ type name
// - require:
// • baseTypeName()
// • isClass()
function typeName(value) {
if (isClass(value)) return "class"; // class
return baseTypeName(value); // other cases
}
📁 module (copy and paste this file to use it)
// ⭐ base type name
function baseTypeName(value) {
// --------------
// ↓ ↱ -1 (index of last character)
// 0123456789012
// ╭──╮
// "[object XXXX]" ╭───╮
// ^^^^ <---- slice(8, -1)
return Object.prototype.toString.call(value).slice(8, -1);
}
/**
* ⭐️ content of function's definition
*
* @throws {TypeError} will throw a TypeError if value is not a function
* @return {string}
*/
function functionDefinition(value) {
// ---------------------------------------------------------------------
// ⭐️ will throw a TypeError if value is not a function:
// ⛔ TypeError:
// Function.prototype.toString requires that 'this' be a Function
// ---------------------------------------------------------------------
return Function.prototype.toString.call(value);
}
// ⭐️ check if value is a function
// - require: baseTypeName()
function isFunction(value) {
return baseTypeName(value) === "Function";
}
// ⭐️ check if value is a "class"
// - require:
// • isFunction()
// • functionDefinition()
function isClass(value) {
return (
// `value` is a function
isFunction(value) &&
// `value` is a "class" definition
functionDefinition(value).startsWith("class")
);
}
// ⭐️ type name
// - require:
// • baseTypeName()
// • isClass()
function typeName(value) {
if (isClass(value)) return "class"; // class
return baseTypeName(value); // other cases
}
// node exports
module.exports = {
baseTypeName,
isFunction,
functionDefinition,
isClass,
typeName,
}
replit:typeName() (v.2)
📁 index.js
// ⭐ import (functions for type name)
const { typeName, baseTypeName } = require('./typeNames.js');
const { testCases } = require('./testCases.js');
// table settings
const header = ['typeof', 'base', 'type', 'expr', 'value'];
const cols = header.length;
const [width, pad, ext] = [12, 1, 10];
const line = '-'.repeat(width*cols + pad*(cols-1) + ext);
// header
console.log(...header.map(s => s.padEnd(width, ' ')));
console.log(line);
// rows
for (const testCase of testCases) {
// separator
if (testCase === '---') {
console.log(line);
continue;
}
// test cases
const value = testCase[0];
const expr = testCase[1] || String(testCase[0]);
const types = [typeof value, baseTypeName(value), typeName(value)];
const numberOfDifferentTypes = new Set(types.map(s => s.toLowerCase())).size;
if (numberOfDifferentTypes > 1) types[0] += '⭐️';
if (baseTypeName(value) !== typeName(value)) types[0] += '❗';
console.log(
...[...types, expr].map(s => s.padEnd(width, ' ')),
value,
)
}
console.log(line);
// legend
console.log(`• ⭐️ types not all the same • ❗ base !== type`);
📁 testCases.js
// custom class
class User {
// ⭐ class field
name = 'JohnDoe';
// ⭐ custom class name
get [Symbol.toStringTag]() { return 'User' }
}
// instance
let user = new User();
// test values: [expr, expr string]
const testCases = [
// ⭐️ null
[null, ],
'---',
// ⭐️ undefined --------------------------------------
[undefined, ],
'---',
// ⭐️ Number --------------------------------------
[37, ],
[3.14, ],
[Math.LN2, 'Math.LN2'],
[Infinity, ],
[NaN, ],
[Number('1'), `Number('1')`], // 1
[Number('abc'), `Number('ab')`], // NaN❗
'---',
// ⭐️ bigInt --------------------------------------
[42n, ],
'---',
// ⭐️ String --------------------------------------
['bla', `'bla'`],
[`x = ${1+2}`, '`x = ${1+2}`'], //
[typeof 1, 'typeof 1'], // always returns a string
[String({}), 'String({})'], // [object]❗
[typeof xxx, 'typeof xxx'], // 'undefined'❗ (string)
'---',
// ⭐️ Boolean --------------------------------------
[true, ],
[Boolean(1), 'Boolean(1)'], // true
[!!(1), '!!(1)'], // true
'---',
// ⭐️ Symbol --------------------------------------
[Symbol(), ],
[Symbol.iterator, 'Symbol.iterator'],
'---',
// ⭐️ objects --------------------------------------
[{ a: 1 }, '{a:1}'], // object literal
[user, 'user'], // instance of User
[[1, 2], '[1, 2]'], // Array
[new Date(), 'new Date()'], // Date
[/regex/, ], // RegExp
'---',
// ⭐️ Functions --------------------------------------
[function(){}, 'function(){}'], // "normal" function
[Math.sin, 'Math.sin'], // method
[() => {}, '() => {}'], // arrow function
[class {}, 'class {}'], // class ⭐️
[User, 'User'], // class ⭐️
[function*(){}, 'function*(){}'], // generator functions
];
// export
module.exports = { User, testCases };
objects can change the behavior of Object.prototype.toString()
by defining a Symbol.toStringTag
property, leading to unexpected results:
const date = new Date();
date[Symbol.toStringTag] = 'XXX';
Date.prototype[Symbol.toStringTag] = 'prototype polluted';
const toString = Object.prototype.toString; // keep it short
toString.call(date); // [object XXX]
toString.call(new Date()); // [object prototype polluted]
Last updated