Symbol.toStringTag
Sets the label Object.prototype.toString() reports for an object.
Symbol.toStringTag
// as implemented on an object:
get [Symbol.toStringTag]()- Added in JavaScript ES2015
Return value
symbolThe well-known symbol whose value Object.prototype.toString() reads to build the string "[object Tag]".
Object.prototype.toString() builds its result by reading this[Symbol.toStringTag]. If that property is a string it becomes the tag; otherwise a builtin fallback applies, giving "[object Object]" for ordinary objects and "[object Array]", "[object Null]" and friends for the special cases.
When to reach for it
Define it when your class is a distinct kind of thing and you want that visible in logs, devtools and the Object.prototype.toString.call(x) idiom still used for type dispatch. Builtins do exactly this: Map, Set, Promise, WeakMap, module namespace objects and generator objects all carry the tag. A getter is the usual form, since the value is looked up on demand.
What trips people up
The tag is a label, not a type. Anyone can set [Symbol.toStringTag] = "Array", so it is cosmetic and must never be a security or correctness check — prefer Array.isArray(), instanceof, or a private field. It also does not change typeof, nor the output of your own toString() if you defined one: String(x) only shows the tag when the object still inherits Object.prototype.toString. Defining it as a plain enumerable data property leaks it into Object.assign() copies, so use a getter or a non-enumerable descriptor.
Example
When to use it
- Give a custom collection class a meaningful label in console output and stack traces
- Keep a legacy Object.prototype.toString.call() type switch working for your own types
- Distinguish several classes in a debug dump without adding a visible property
Frequently asked questions
How do I stop my class printing as [object Object]?
Add a getter keyed by Symbol.toStringTag that returns the name you want, and Object.prototype.toString.call(instance) will report [object YourName]. Define toString() as well if you want String(instance) to change too.
Does Symbol.toStringTag change typeof?
No. typeof still returns 'object' for any object regardless of its tag; only Object.prototype.toString() and console formatting are affected.
Is Object.prototype.toString.call() a reliable type check?
Not any more. Because Symbol.toStringTag can be set to any string, an object can impersonate a builtin, so use Array.isArray(), instanceof, or private-field brand checks when correctness matters.
More examples
A type-name helper built on the tag
The helper reads real tags for builtins, but the last line shows a plain object claiming to be an Array — typeName says "Array" while Array.isArray() correctly says false.
const typeName = (v) => Object.prototype.toString.call(v).slice(8, -1);
console.log(typeName(new Map()));
console.log(typeName(Promise.resolve()));
console.log(typeName(undefined));
console.log(typeName(/x/));
const fake = { [Symbol.toStringTag]: "Array" };
console.log(typeName(fake), Array.isArray(fake));A custom toString() takes over
Because Tagged defines its own toString(), String() and template literals use that instead of the tag. The tag still surfaces when Object.prototype.toString is called explicitly.
class Tagged {
get [Symbol.toStringTag]() {
return "Tagged";
}
toString() {
return "custom text";
}
}
const t = new Tagged();
console.log(String(t));
console.log(`${t}`);
console.log(Object.prototype.toString.call(t));
Discussion