Skip to content

Commit 1f048cb

Browse files
authored
Fix: no-implicit-coercion false positive with String() (fixes #14623) (#14641)
1 parent d709abf commit 1f048cb

2 files changed

Lines changed: 31 additions & 3 deletions

File tree

lib/rules/no-implicit-coercion.js

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,20 @@ function getNonNumericOperand(node) {
109109
return null;
110110
}
111111

112+
/**
113+
* Checks whether an expression evaluates to a string.
114+
* @param {ASTNode} node node that represents the expression to check.
115+
* @returns {boolean} Whether or not the expression evaluates to a string.
116+
*/
117+
function isStringType(node) {
118+
return astUtils.isStringLiteral(node) ||
119+
(
120+
node.type === "CallExpression" &&
121+
node.callee.type === "Identifier" &&
122+
node.callee.name === "String"
123+
);
124+
}
125+
112126
/**
113127
* Checks whether a node is an empty string literal or not.
114128
* @param {ASTNode} node The node to check.
@@ -126,8 +140,8 @@ function isEmptyString(node) {
126140
*/
127141
function isConcatWithEmptyString(node) {
128142
return node.operator === "+" && (
129-
(isEmptyString(node.left) && !astUtils.isStringLiteral(node.right)) ||
130-
(isEmptyString(node.right) && !astUtils.isStringLiteral(node.left))
143+
(isEmptyString(node.left) && !isStringType(node.right)) ||
144+
(isEmptyString(node.right) && !isStringType(node.left))
131145
);
132146
}
133147

@@ -332,6 +346,11 @@ module.exports = {
332346
return;
333347
}
334348

349+
// if the expression is already a string, then this isn't a coercion
350+
if (isStringType(node.expressions[0])) {
351+
return;
352+
}
353+
335354
const code = sourceCode.getText(node.expressions[0]);
336355
const recommendation = `String(${code})`;
337356

tests/lib/rules/no-implicit-coercion.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,16 @@ ruleTester.run("no-implicit-coercion", rule, {
9595
{ code: "`${foo}`", parserOptions: { ecmaVersion: 6 } },
9696
{ code: "`${foo}`", options: [{ }], parserOptions: { ecmaVersion: 6 } },
9797
{ code: "`${foo}`", options: [{ disallowTemplateShorthand: false }], parserOptions: { ecmaVersion: 6 } },
98-
"+42"
98+
"+42",
99+
100+
// https://github.com/eslint/eslint/issues/14623
101+
"'' + String(foo)",
102+
"String(foo) + ''",
103+
{ code: "`` + String(foo)", parserOptions: { ecmaVersion: 6 } },
104+
{ code: "String(foo) + ``", parserOptions: { ecmaVersion: 6 } },
105+
{ code: "`${'foo'}`", options: [{ disallowTemplateShorthand: true }], parserOptions: { ecmaVersion: 6 } },
106+
{ code: "`${`foo`}`", options: [{ disallowTemplateShorthand: true }], parserOptions: { ecmaVersion: 6 } },
107+
{ code: "`${String(foo)}`", options: [{ disallowTemplateShorthand: true }], parserOptions: { ecmaVersion: 6 } }
99108
],
100109
invalid: [
101110
{

0 commit comments

Comments
 (0)