Type Utilities IILoading saved progress…

Type Utilities II

Implement a set of runtime predicates that accurately answer "what kind of object is this?" for the common non-primitive JavaScript values: isArray, isPlainObject, isDate, isMap, isSet, and isRegExp. These are the checks a library runs internally before deciding how to clone, serialize, or merge a value. The reliable way to do it is the value's built-in tag, read with Object.prototype.toString.call(value) — it returns strings like '[object Date]' and '[object Map]', one per kind of value. (A sibling "Type Utilities" question covers primitives; here you handle the object side.)

These are runtime checks on real values — not TypeScript type guards. Every predicate takes one argument and returns a strict boolean.

Signature

// Each predicate takes any value and returns a strict boolean (true | false).
// Implement at least these six; isError and isPromise are optional extras.
function isArray(value: unknown): boolean;       // true for [], [1,2]
function isPlainObject(value: unknown): boolean; // true for {}, Object.create(null)
function isDate(value: unknown): boolean;        // true for any Date object
function isMap(value: unknown): boolean;         // true for a real Map
function isSet(value: unknown): boolean;         // true for a real Set
function isRegExp(value: unknown): boolean;      // true for /x/, new RegExp()

Examples

// isArray cares about real arrays, not anything that merely has a length.
isArray([1, 2, 3]); // → true
isArray({ length: 0 }); // → false  (array-like, but not an array)
isArray('abc'); // → false  (has a length, still not an array)
// isPlainObject is the subtle one: a bag of keys, not a built-in or instance.
isPlainObject({ a: 1 }); // → true
isPlainObject(Object.create(null)); // → true  (no prototype, still a plain bag)
isPlainObject(new Date()); // → false  (a Date, not a plain object)
isPlainObject(new (class Foo {})()); // → false  (a class instance)

Notes

  • Use the tag, not instanceof. value instanceof Date works in one frame but returns false for a Date created in another iframe or worker, because each realm has its own Date constructor. Object.prototype.toString.call(value) returns the same tag everywhere, so it's the dependable check.
  • isPlainObject is a two-step decision. The tag '[object Object]' is necessary but not sufficient — a class Foo {} instance shares that tag. After the tag check, also confirm the prototype is Object.prototype or null.
  • A Date is a Date even when it's invalid. new Date('nonsense') holds NaN time but is still a Date object, so isDate returns true. You're checking the kind of value, not whether its contents are valid.
  • Distinguish the value from its string form. isRegExp('/x/') is false — that's a string. isDate(Date.now()) is false — that's a number. Only the real object counts.
  • Never throw on null or undefined. Each predicate must return false for both, not crash. Object.prototype.toString.call(null) safely returns '[object Null]'.
  • Return a strict boolean. true or false, never a truthy object or undefined. A === '[object …]' comparison gives you that for free.
Loading editor…