JavaScript Basics: Classify Built-In Values with util.types
Values from another JavaScript realm can fail ordinary instanceof checks. Node’s util.types offers built-in type predicates for diagnostic and interoperability code. A trusted fixed VM expression creates a cross-realm Date for comparison.
Prepare a scratch directory
Tested on Linux with Node.js v24.19.0. You need the named runtime, Bash, a text editor, and the standard mktemp, rm, and rmdir utilities. The .mjs extension selects ES modules. Assertions check the demonstrated behavior; no npm packages or remote services are needed.
Keep using the same terminal. Stop if setup fails, before saving the source:
start_dir="$PWD"
work_dir="$(mktemp -d)" || exit 1
cd -- "$work_dir" || exit 1Run the example
Save this as demonstrate-util-types.mjs:
import assert from 'node:assert/strict';
import { types } from 'node:util';
import vm from 'node:vm';
const foreignDate = vm.runInNewContext('new Date(0)');
assert.equal(foreignDate instanceof Date, false);
assert.equal(types.isDate(foreignDate), true);
console.log('Foreign Date instanceof local Date:', foreignDate instanceof Date);
console.log('Foreign Date recognized by util.types:', types.isDate(foreignDate));
const disguised = { [Symbol.toStringTag]: 'Map' };
assert.equal(Object.prototype.toString.call(disguised), '[object Map]');
assert.equal(types.isMap(disguised), false);
assert.equal(types.isMap(new Map()), true);
console.log('Display tag can say:', Object.prototype.toString.call(disguised));
console.log('Disguised value is a Map:', types.isMap(disguised));
const bytes = new Uint8Array(4);
const view = new DataView(bytes.buffer);
assert.equal(types.isTypedArray(bytes), true);
assert.equal(types.isTypedArray(view), false);
assert.equal(types.isArrayBufferView(view), true);
console.log('DataView is typed array:', types.isTypedArray(view));
console.log('DataView is buffer view:', types.isArrayBufferView(view));Run it:
node demonstrate-util-types.mjsObserved output:
Foreign Date instanceof local Date: false
Foreign Date recognized by util.types: true
Display tag can say: [object Map]
Disguised value is a Map: false
DataView is typed array: false
DataView is buffer view: trueRead the result
The foreign Date has another realm’s prototype, so the local constructor’s instanceof check fails. The built-in predicate still recognizes the value. A custom string tag can alter a display label without creating a real Map. The final checks distinguish typed arrays from the broader family of ArrayBuffer views, which also includes DataView.
Apply it carefully
These predicates classify values; they do not validate application schemas, guarantee safe methods, or inspect every nested member. Cross-realm objects can still need normalization before use. The VM call executes only a fixed trusted expression here; Node’s VM API should not be used as an untrusted-code security boundary. Prefer simple language checks such as Array.isArray when they already express the contract you need.
The official reference describes the API and its options. The checks above cover the specific fixture, not every possible input or environment.
Clean up
Remove the source and then the empty practice directory:
rm -- demonstrate-util-types.mjs
cd -- "$start_dir" || exit 1
rmdir -- "$work_dir"
unset start_dir work_dirIf the directory is not empty, inspect the remaining files rather than deleting unknown contents.
Acknowledgements
This post was created with assistance from AI.