Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[no-base-to-string] False positive for tagged tepmplates #1757

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
susisu opened this issue Mar 17, 2020 · 6 comments · Fixed by #1763
Closed

[no-base-to-string] False positive for tagged tepmplates #1757

susisu opened this issue Mar 17, 2020 · 6 comments · Fixed by #1763
Labels
enhancement: plugin rule option New rule option for an existing eslint-plugin rule good first issue Good for newcomers has pr there is a PR raised to close this package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin

Comments

@susisu
Copy link
Contributor

susisu commented Mar 17, 2020

Repro

{
  "parser": "@typescript-eslint/parser",
  "plugins": ["@typescript-eslint"],
  "parserOptions": {
    "ecmaVersion": 2019,
    "sourceType": "module",
    "project": "./tsconfig.json"
  },
  "rules": {
    "@typescript-eslint/no-base-to-string": "error"
  }
}
declare function tag(xs: TemplateStringsArray, ...ys: unknown[]): void;
tag`${{}}`;

Expected Result
No lint errors because the tag does not necessarily stringify the interpolated values.

Actual Result
Lint error is reported.
2:7 error '{} will evaluate to '[Object object]' when stringified @typescript-eslint/no-base-to-string

Additional Info

Versions

package version
@typescript-eslint/eslint-plugin 2.24.0 and 2.24.1-alpha.0
@typescript-eslint/parser 2.24.0 and 2.24.1-alpha.0
TypeScript 3.7.5
ESLint 6.8.0
node 12.14.1
npm 6.13.4
@susisu susisu added package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin triage Waiting for team members to take a look labels Mar 17, 2020
@bradzacher
Copy link
Member

happy to accept a PR here.
A new option like ignoreTaggedTemplateExpressions: boolean would probably be good, to keep this backwards-compatible.

@bradzacher bradzacher added enhancement: plugin rule option New rule option for an existing eslint-plugin rule good first issue Good for newcomers and removed triage Waiting for team members to take a look labels Mar 17, 2020
@susisu
Copy link
Contributor Author

susisu commented Mar 18, 2020

I would like to try to create a PR for this.

@LinusU
Copy link
Contributor

LinusU commented Apr 17, 2020

Hmm, @bradzacher would you mind elaborating on why we made this change behind a flag for "backwards compatibility"? To me, it seems like the lint just doesn't apply to template literals, since they aren't strings.


e.g. take a look at this function with the default config:

declare class Foo {}
declare function tag (xs: TemplateStringsArray, ...ys: Foo[]): void

const a = new Foo()
const b = new Foo()

tag`
 a: ${a}
 b: ${b}
`

Here the only valid things to pass inside an interpolation is a Foo, and there is no need for it to be stringified at all. In fact, it will only be stringified if tag explicitly does that, and since it has declared Foo as the input it probably knows what it's doing...

Also, in this example, the error message is completely irrelevant 😄

'{} will evaluate to '[Object object]' when stringified

I mean, it's true, but nothing is being stringified here 😄


Or maybe I'm missing something? 🤔

@bradzacher
Copy link
Member

I wasn't thinking overly hard about it at the time. With a lot of issues and PRs being raised, I'm not always on the ball when thinking about solutions to things I'm not 100% familiar with.

I haven't used custom template tags much, so on the surface I thought that there might be cases where you do want it to check tagged templates. But looking now, I realise that I'm flat out wrong.

The case I was thinking of was when the arguments are typed as string. I didn't realise that the a tagged template with ...ys: string[] would cause type errors:

declare class Foo {}
declare function tag (xs: TemplateStringsArray, ...ys: string[]): void

const a = new Foo()
const b = new Foo()

tag`
 a: ${a} // Argument of type 'Foo' is not assignable to parameter of type 'string'.
 b: ${b} // Argument of type 'Foo' is not assignable to parameter of type 'string'.
`

Seeing now that this option really shouldn't even exist, happy to accept a PR to switch it over to default true, with the intention of us removing it in the next major.
(Normally switching a default option value is breaking, but considering the rule is broken with it false, I think it's not actually a breaking change)

@susisu
Copy link
Contributor Author

susisu commented Apr 18, 2020

My first thought was the same as @LinusU, but I added the option that @bradzacher suggested because I thought there might be and actually are tag functions that intentionally take any substitutions.
For example, the signature of the built-in String.raw function is

raw(template: TemplateStringsArray, ...substitutions: any[]): string;

, and in this case I think it is better to check that interpolated values can be stringified in meaningful ways.
I'm not sure how tagged templates are commonly used, but I think the options is not such bad.

@bradzacher
Copy link
Member

bradzacher commented Apr 18, 2020

That's definitely a valid concern, but the fact that String.raw stringifies the substitutions under the hood is an implementation detail of the tag.
So treating all tags as unsafe for this (relatively) edge case does seem like the wrong approach.

For tags custom to the codebase that use any, there's a large safety hole anyway if they just do something like x += substitution[i] + "". If the code does type refinement to refine to a usable type, then this rule will come into effect anyway.

Two better approaches to solve this problem:

  • We could build in handling for the standard library function(s) with a known implementation.
    • We've done similar things before in other rules, such as unbound-method.
  • We could add an option to treat tags with any typed substitutions as potential stringifiers.
    • This severely narrows the scope of the option, and likely wouldn't flag on most things in a codebase.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 19, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement: plugin rule option New rule option for an existing eslint-plugin rule good first issue Good for newcomers has pr there is a PR raised to close this package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin
Projects
None yet
3 participants