Skip to content

Transpiled template literals behave incorrectly #39744

Closed
@lowr

Description

@lowr

TypeScript Version: 3.9.7, 4.0.0-dev.20200725

Search Terms:

template literals, template strings, ES5, ES3

Code

class C {
    toString() {
        return "toString()";
    }
    valueOf() {
        return "valueOf()";
    }
}

const c = new C;
const s = `${c}`;
console.log(s);

Expected behavior:

According to ES2015 (and later) spec, the result of expressions in template literals are converted to primitives first by calling toString() and then by valueOf() (unless there is [Symbol.toPrimitive](), but I'll just ignore it here as Symbols wouldn't get transpiled). s therefore evaluates to "toString()".

Actual behavior:

s evaluates to "valueOf()".

The above code is compiled to the following when the target is ES5 or ES3. + operator attempts to convert its operands to primitives first by calling valueOf() and then by toString(), which is the opposite of the expected behavior.

"use strict";
var C = /** @class */ (function () {
    function C() {
    }
    C.prototype.toString = function () {
        return "toString()";
    };
    C.prototype.valueOf = function () {
        return "valueOf()";
    };
    return C;
}());
var c = new C;
var s = "" + c;
console.log(s);

FWIW, Babel compiles the above code to this unless loose transformation is enabled. It makes use of String.prototype.concat() and behaves as expected.

Playground Link: Link

Related Issues:

#30239: Although OP's suggestion is not related, some people commenting on the issue seem to confront this issue (like this comment)

Metadata

Metadata

Assignees

Labels

Fix AvailableA PR has been opened for this issueNeeds InvestigationThis issue needs a team member to investigate its status.RescheduledThis issue was previously scheduled to an earlier milestone

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions