Skip to content

Bug: [no-base-to-string] generate error with type filter above #11011

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
4 tasks done
KuSh opened this issue Mar 31, 2025 · 8 comments
Closed
4 tasks done

Bug: [no-base-to-string] generate error with type filter above #11011

KuSh opened this issue Mar 31, 2025 · 8 comments
Labels
bug Something isn't working locked due to age Please open a new issue if you'd like to say more. See https://typescript-eslint.io/contributing. package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin working as intended Issues that are closed as they are working as intended

Comments

@KuSh
Copy link
Contributor

KuSh commented Mar 31, 2025

Before You File a Bug Report Please Confirm You Have Done The Following...

  • I have tried restarting my IDE and the issue persists.
  • I have updated to the latest version of the packages.
  • I have searched for related issues and found none that matched my issue.
  • I have read the FAQ and my problem is not listed.

Playground Link

https://typescript-eslint.io/play/#ts=5.8.2&fileType=.tsx&code=MYewdgzgLgBApgJwSBBZOEIEMDmcYC8MAFIsggFwwCuYA1mCAO5gCUV0CAlmDoQHwwA3gCgYMLgDMSUAJ4AHOCGlkUhAkQDkIAEYArOMCibWMBHCjUEYGACkAygHkAcgDpOPHFNmkkKVgDcYmYWVjb2UNy8vuSBIgC%2BQUA&eslintrc=N4KABGBEBOCuA2BTAzpAXGUEKQAIBcBPABxQGNoBLY-AWhXkoDt8B6Jge1oCMBDZRLXxdk%2BKkwDm6KImjQO0SODABfECqA&tsconfig=N4KABGBEDGD2C2AHAlgGwKYCcDyiAuysAdgM6QBcYoEEkJemy0eAcgK6qoDCAFutAGsylBm3TgwAXxCSgA&tokens=false

Repro Code

export const errorMessage = (error: unknown): string => {
  if (typeof error === 'object') return JSON.stringify(error);
  return String(error);
};

ESLint Config

module.exports = {
  "rules": {
    "@typescript-eslint/no-base-to-string": "error"
  }
}

tsconfig

{
  "compilerOptions": {
    "strictNullChecks": true
  }
}

Expected Result

No error

Actual Result

'error' may use Object's default stringification format ('[object Object]') when stringified. 3:17 - 3:22

Additional Info

Could be related to the fact that typescript consider the object to be {} | undefined after the test

@KuSh KuSh added bug Something isn't working package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin triage Waiting for team members to take a look labels Mar 31, 2025
@bradzacher
Copy link
Member

Why do you expect there to be no error here?
As far as the types are declared -- there is no toString method declared on the type {} | undefined -- so it's going to use the default toString.
This is working as expected.

@bradzacher bradzacher closed this as not planned Won't fix, can't repro, duplicate, stale Mar 31, 2025
@bradzacher bradzacher added working as intended Issues that are closed as they are working as intended and removed triage Waiting for team members to take a look labels Mar 31, 2025
@KuSh
Copy link
Contributor Author

KuSh commented Mar 31, 2025

Why do you expect there to be no error here? As far as the types are declared -- there is no toString method declared on the type {} | undefined -- so it's going to use the default toString. This is working as expected.

But {} falls in the typeof {} === "object" case so this can never happen, see console.log when running this typescript playground. no [object Object] output

So in that particular case, there's no toString method involved at all, only string coercion

@bradzacher
Copy link
Member

Hover over the type and you'll see what TS narrows it to and why my comment will apply.
The rule is solely powered by types.

@KuSh
Copy link
Contributor Author

KuSh commented Mar 31, 2025

So, if I read between the lines, I'd rather should report that to typescript?

@kirkwaiblinger
Copy link
Member

So, if I read between the lines, I'd rather should report that to typescript?

You can try but likely this would be considered working as intended on their part. In theory maybe something like string | number | bigint | symbol | undefined | Function | boolean would be a better type but it's a little hazy because functions can be objects. Also there's the whole {} can of worms (see also microsoft/TypeScript#60582)

In any case, for our part, there's no generalizable way to distinguish between {} | undefined which is intended literally, and therefore, to which any object might be assigned, and a {} | undefined which is the result of a TS narrowing that (almost certainly) wouldn't actually be reachable at runtime by any non-toString() objects. Likely an eslint-disable comment is your best bet here.

@Josh-Cena
Copy link
Member

functions can be objects

Functions always have typeof === "function".

@kirkwaiblinger
Copy link
Member

functions can be objects

Functions always have typeof === "function".

Oh, yeah. I couldn't remember whether it was "technically not all functions are typeof === 'function'" or "technically not all functions are instanceof Function" (it's the latter). Regardless I also meant to be vague enough to allude to the opposite direction, that (runtime value) () => {} is assignable to (type) {}.

@KuSh
Copy link
Contributor Author

KuSh commented Apr 1, 2025

Thanks @kirkwaiblinger for all the explanations and the context.

For the record a simple fix is to test both for nullness AND typeof.
With that error stays unknown after the condition and the linting error goes out

export const errorMessage = (error: unknown): string => {
  if (error !== null && typeof error === 'object') return JSON.stringify(error);
  return String(error);
};

@github-actions github-actions bot added the locked due to age Please open a new issue if you'd like to say more. See https://typescript-eslint.io/contributing. label Apr 9, 2025
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 9, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug Something isn't working locked due to age Please open a new issue if you'd like to say more. See https://typescript-eslint.io/contributing. package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin working as intended Issues that are closed as they are working as intended
Projects
None yet
Development

No branches or pull requests

4 participants