Skip to content

TypeScript's code formatting corrupts code containing a numeric literalΒ #50686

@evanw

Description

@evanw

Bug Report

πŸ”Ž Search Terms

formatter number tostring

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

1+ 2 .toString() +3

πŸ™ Actual behavior

When you run "Format Document" the code is changed to 1 + 2.toString() + 3, which is invalid JavaScript.

πŸ™‚ Expected behavior

Several valid formatting outputs include the following:

1 + 2 .toString() + 3
1 + 2..toString() + 3
1 + (2).toString() + 3

This is a problem for VSCode users because it means that saving a file in VSCode corrupts the file (if you have format-on-save enabled). And it's a problem for me as the author of esbuild because people are running VSCode's formatter on esbuild's output and then reporting the corrupted code as a bug in esbuild: evanw/esbuild#2528.

Side note: How to run TypeScript's formatter yourself

I had to manually run TypeScript's formatter to confirm that the problem was with the code in this repo. Running TypeScript's formatter on a string was unexpectedly difficult because the API is not exposed and is only available through the language server protocol, which seemed way too complicated to invoke manually. I instead used a hack that loads the code in tsserver.js to get to the formatter. Posting the hack here for posterity:

const input = '1+ 2 .toString() +3'
const process = undefined
const addEventListener = () => {}
var ts = {}
const serverFile = require.resolve('typescript/lib/tsserver')
const serverCode = require('fs').readFileSync(serverFile, 'utf8')
eval(serverCode.replace('\n"use strict";\n', ''))
const sourceFile = ts.createSourceFile('in.js', input)
const options = ts.getDefaultFormatCodeSettings()
const context = ts.formatting.getFormatContext(options, {})
const changes = ts.formatting.formatDocument(sourceFile, context)
console.log('before:', input)
console.log('after:', ts.textChanges.applyChanges(input, changes))

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptFix AvailableA PR has been opened for this issue

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions