With these declarations your fragment is valid in both JavaScript and TypeScript:
class b {}
class c {}
const d = JSON.parse
const a = Promise.prototype.then.bind(Promise.resolve(1))
console.log(a<b,c>(d))
// TS output: Promise { <state>: "pending" }
// JS output: false false
It is strictly true. a<b,c>(d) is only valid JavaScript iff a, b, c, and d are values.
The TypeScript expression a<b,c>(d) where b and c are types is NOT JavaScript, since JavaScript doesn't have type expressions. The statement that every JavaScript program is a valid TypeScript program does not imply the opposite - hence strict superset.
edit: there is indeed an edge case with the parentheses that throws the TypeScript parser off even if only values are involved.
See the sibling comment from oblosys for an example where the exact same code can give different results in vanilla JS vs after a tsc pass. As you can see there, the problem is that an identifier can simultaneously represent a value and a type.
This is different than JSX or hashbang, where the set of non-JS syntax cannot legally overlap with existing syntax/semantics.
I guess this is a distinction between intent and results. Typescript is intended to be a strict superset of Javascript. In practice, there are edge cases like these.