Symbol.toStringTag

Sets the label Object.prototype.toString() reports for an object.

Signature
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

Try it yourself
Loading editor…
Press Run to execute the code.

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.

Example · javascript
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.

Example · javascript
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

  • Be the first to comment on this lesson.