June 13, 2018·4 min read·engineeringtypescriptjsoncompiler

TypeScript 2.9.2 keeps JavaScript emission rules out of JSON files

TypeScript 2.9.2 corrects JSON output under strict-mode, trailing-comma and source-map settings. The fixes preserve the distinction between a typed build input and an executable JavaScript source file.

A JSON file can participate in a TypeScript build without becoming JavaScript. That distinction becomes important when the compiler shares machinery among different source-file kinds. A strict-mode directive belongs in generated JavaScript, while the JSON output must remain data that a JSON reader can consume. TypeScript 2.9.2 includes corrections at that boundary.

The npm registry records the maintenance release on June 13. Its changes since 2.9.1 include fixes for strict-mode prologues and trailing commas in JSON emission, plus changes to declaration and source-map handling. The tagged patch and its expected-output tests establish the intended behaviour for these build configurations directly.

I find TypeScript valuable when its build tooling supports the framework and runtime semantics a web application actually uses. Typed JSON imports are useful in that context, but checking a file's properties is only part of the work. The output artifact still has to be a valid input for the consumer that loads it.

Strictness applies differently to code and data

TypeScript 2.9 introduced resolveJsonModule, allowing JSON imports to acquire types from their contents and carry the JSON into the output directory. The 2.9 announcement illustrates the feature with boolean configuration values and a diagnostic for comparing one with a number.

Version 2.9.2 repairs the interaction with alwaysStrict. The transformation previously considered whether to insert a strict-mode prologue without excluding JSON source files. The patch adds an isJsonSourceFile() check to that decision.

Its regression fixture enables CommonJS output, JSON-module resolution and alwaysStrict. The expected JavaScript starts with the strict directive. The emitted JSON contains only the original data structure. These different outputs show that the fix preserves strict code generation while excluding a file kind to which that directive does not belong.

The distinction is not cosmetic. A directive written before a JSON object is additional program syntax, not part of that object's serialized data. A consumer expecting JSON cannot interpret a JavaScript prologue as an instruction about how strictly to read the following object.

This is also why disabling strictness for an entire application would answer the wrong problem. The source correction narrows where the directive is eligible for emission. It lets the existing JavaScript policy remain in force while maintaining the JSON artifact's own format.

Trailing commas need an output-format check

Another patch changes object-literal emission so the option to preserve a trailing comma excludes JSON source files. Previously the decision depended on the script target being at least ES5. That target test describes JavaScript syntax support, but JSON emission needs a separate condition.

The regression fixture supplies a JSON object with a trailing comma. Its output baseline removes that comma from the generated JSON. The importing TypeScript file still emits an ordinary CommonJS load of the JSON path, so the output data file must stand on its own as JSON.

This is a useful example of the difference between accepting an input representation and choosing an output representation. A compiler can parse a structure into a common internal form, then emit it under the rules of the destination file kind. Sharing the representation does not imply that every supported punctuation choice belongs in every output format.

The patch changes one eligibility expression, but its test checks the actual data artifact. That is the relevant contract for a runtime consumer. A checker-only test would establish property types without showing whether the file written to disk still has the expected serialization syntax.

Source maps and declarations also need file-kind boundaries

The maintenance series disables source maps and declaration emission for JSON modules. Its source-map implementation adds JSON checks while initializing mapping output, recording positions and producing a source-map URL. Those checks prevent JavaScript-oriented mapping machinery from treating the data file like an emitted script.

The tests retain a source map for the generated importing JavaScript file. Their expected JSON output has no appended mapping comment. A separate declaration-emission fixture keeps the TypeScript module's declaration output while retaining the JSON as data. The build therefore contains different artifact categories with different permitted companions.

The patch also adjusts the compiler's own test machinery to count JavaScript outputs separately from JSON outputs when checking declaration and map counts. This makes the tests reflect the distinction enforced by the implementation. Adding a new input kind affects the assumptions in verification code as well as in the production emitter.

My judgement is that these corrections complete an essential part of typed JSON imports. The compiler needs to infer useful property types, preserve the imported file's runtime path and emit data under the rules of its format. TypeScript 2.9.2 addresses the output-format part through explicit source-file checks and regression baselines for the resulting artifacts.