An object that doesn't define its own toString() turns into the text "[object Object]". That text ends up in a log line, a URL or a message on the page, and the data you wanted to show is lost.
The rule checks .toString(), .toLocaleString(), String(value), "text" + value, ${value} in a template, and .join() on an array of such objects. The report says "will" if the type always gives [object Object], and "may" if only some members of a union do.
bun lint --type-aware turns this rule on in TypeScript files.
Configure
Off by default. This rule needs types, so turning it on makes bun lint type check your code first.
[lint.rules]
"@typescript-eslint/no-base-to-string" = "error" # or "warn"
Every option, set to its default:
[lint.rules]
"@typescript-eslint/no-base-to-string" = ["error", {
ignoredTypeNames = ["Error", "RegExp", "URL", "URLSearchParams"],
checkUnknown = false,
}]
Examples
Reported:
const user = { name: "Ada" };
console.log(`Hello, ${user}`);
console.log("Hello, " + user);
console.log([user].join(", "));
Not reported:
const user = { name: "Ada" };
console.log(`Hello, ${user.name}`);
console.log(JSON.stringify(user));
class Point {
constructor(private x: number, private y: number) {}
toString(): string {
return `${this.x},${this.y}`;
}
}
console.log(`At ${new Point(1, 2)}`);
Options
| Option | Default | What it does |
|---|---|---|
ignoredTypeNames | ["Error", "RegExp", "URL", "URLSearchParams"] | Names of types that are never reported. Types that extend them aren't reported either. Your list replaces the default. |
checkUnknown | false | Also report values of type unknown, which may be plain objects. |
interface Money {
amount: number;
}
declare const price: Money;
console.log(`Total: ${price}`);
function describe(value: unknown): string {
return `Got ${value}`;
}