A zero-dependency utility for retrieving Object.prototype.toString tags. It is designed to handle hostile or exotic objects that cause native implementations to throw exceptions.
The native Object.prototype.toString.call() API can throw when encountering certain object states (for example revoked proxies or throwing Symbol.toStringTag getters). This library provides a wrapper that returns a string without propagating those exceptions.
- Revoked Proxies: Avoids
TypeErroron revoked proxies. - Throwing Getters: Handles
Symbol.toStringTaggetters that throw. - Null/Undefined: Returns consistent strings for nullish values.
- Masked Tags: By default, respects custom
Symbol.toStringTagvalues; useunmaskTagto explicitly reveal the underlying tag when needed.
npm install @scrrlt/safe-tagimport safeTag, { unmaskTag } from "@scrrlt/safe-tag";
// Standard types
safeTag(123); // "[object Number]"
safeTag([]); // "[object Array]"
// Hostile types
const { proxy, revoke } = Proxy.revocable({}, {});
revoke();
safeTag(proxy); // "[object Object]" (does not throw)
// Custom tags
const obj = { [Symbol.toStringTag]: "Custom" };
safeTag(obj); // "[object Custom]" (read-only)
unmaskTag(obj); // "[object Object]" (temporarily mutates Symbol.toStringTag)- Returns: A string in the form
[object Type]. - Exception handling: Guaranteed not to throw. For hostile objects (like revoked proxies), returns
"[object Object]". - Behavior: Returns the tag as the engine sees it. Respects
Symbol.toStringTagmasks and never mutates the input.
Advanced API that attempts to reveal the underlying tag by temporarily mutating the object's own Symbol.toStringTag descriptor.
- Risk: May cause V8 to de-optimize the object (hidden class changes) due to descriptor mutation.
- Side effects: Temporarily mutates
Symbol.toStringTagon the object during the read, but is designed to restore the original descriptor and never throws. Falls back tosafeTag(value)if unmasking fails.
For environments where inputs are trusted and performance is prioritized over resilience:
fastTag: Minimal wrapper aroundObject.prototype.toString.call(). Fastest, but may throw on revoked proxies or hostile objects.
- Build:
npm run build - Typecheck:
npm run typecheck - Tests (dist):
npm run test:all - Tests (src, faster dev loop):
npm run test:src:all - Benchmarks:
npm run bench
MIT