diff --git a/src/rules/restrictPlusOperandsRule.ts b/src/rules/restrictPlusOperandsRule.ts index ea6848e8e88..8ad61e2090c 100644 --- a/src/rules/restrictPlusOperandsRule.ts +++ b/src/rules/restrictPlusOperandsRule.ts @@ -52,7 +52,7 @@ function walk(ctx: Lint.WalkContext, tc: ts.TypeChecker) { const rightType = tc.getTypeAtLocation(node.right); const rightTypeStr = getBaseTypeOfLiteralType(rightType); if (leftTypeStr === "invalid" || rightTypeStr === "invalid" || leftTypeStr !== rightTypeStr) { - const actualTypes = `, but found ${tc.typeToString(leftType, node)} + ${tc.typeToString(rightType, node)}`; + const actualTypes = `, but found ${getTypeString(tc, node.left, leftType)} + ${getTypeString(tc, node.right, rightType)}`; let message = Rule.INVALID_TYPES_ERROR + actualTypes; if (leftTypeStr === "string" || rightTypeStr === "string") { message += Rule.SUGGEST_TEMPLATE_LITERALS; @@ -64,6 +64,15 @@ function walk(ctx: Lint.WalkContext, tc: ts.TypeChecker) { }); } +function getTypeString(tc: ts.TypeChecker, node: ts.Node, type: ts.Type) { + const typeString = tc.typeToString(type, node); + if (typeString === "undefined[]" && ts.isArrayLiteralExpression(node) && !node.elements.length) { + // Special case literal "[]" arrays that would otherwise be emitted as undefined[]. + return "[]"; + } + return typeString; +} + function getBaseTypeOfLiteralType(type: ts.Type): "string" | "number" | "invalid" { if ( isTypeFlagSet(type, ts.TypeFlags.StringLiteral) || diff --git a/test/rules/restrict-plus-operands/test.ts.lint b/test/rules/restrict-plus-operands/test.ts.lint index 44b5ffb8e51..4899d42ced7 100644 --- a/test/rules/restrict-plus-operands/test.ts.lint +++ b/test/rules/restrict-plus-operands/test.ts.lint @@ -19,13 +19,13 @@ var pair: NumberStringPair = { var bad1 = 5 + "10"; ~~~~~~~~ [Operands of '+' operation must either be both strings or both numbers, but found 5 + "10". Consider using template literals.] var bad2 = [] + 5; - ~~~~~~ [Operands of '+' operation must either be both strings or both numbers, but found undefined[] + 5] + ~~~~~~ [Operands of '+' operation must either be both strings or both numbers, but found [] + 5] var bad3 = [] + {}; - ~~~~~~~ [Operands of '+' operation must either be both strings or both numbers, but found undefined[] + {}] + ~~~~~~~ [Operands of '+' operation must either be both strings or both numbers, but found [] + {}] var bad4 = [] + []; - ~~~~~~~ [Operands of '+' operation must either be both strings or both numbers, but found undefined[] + undefined[]] + ~~~~~~~ [Operands of '+' operation must either be both strings or both numbers, but found [] + []] var bad4 = 5 + []; - ~~~~~~ [Operands of '+' operation must either be both strings or both numbers, but found 5 + undefined[]] + ~~~~~~ [Operands of '+' operation must either be both strings or both numbers, but found 5 + []] var bad5 = "5" + {}; ~~~~~~~~ [Operands of '+' operation must either be both strings or both numbers, but found "5" + {}. Consider using template literals.] var bad6 = 5.5 + "5"; @@ -39,7 +39,7 @@ var bad9 = y + x; var bad10 = x + {}; ~~~~~~ [Operands of '+' operation must either be both strings or both numbers, but found number + {}] var bad11 = [] + y; - ~~~~~~ [Operands of '+' operation must either be both strings or both numbers, but found undefined[] + string. Consider using template literals.] + ~~~~~~ [Operands of '+' operation must either be both strings or both numbers, but found [] + string. Consider using template literals.] var bad12 = pair.first + "10"; ~~~~~~~~~~~~~~~~~ [Operands of '+' operation must either be both strings or both numbers, but found number + "10". Consider using template literals.] var bad13 = 5 + pair.second;