> I would love if a compiler expert could chime in here, but my understanding is you could never write a Typescript compiler that was “strongly” typed because there is no data structure that can efficiently represent arbitrary types like “4 Or An Object With An Attribute Set To 4” in any meaningful way.
(I don't consider myself a compiler expert by any means, but I've been doing it for nearly 20 years, so I feel relatively safe weighing in here.)
In short, if you were compiling a function like that for bare metal (or anything relatively like it), there would be no one function that takes in all of those types and acts on them. Instead, you would compile that function once for each combination of incoming types. The version that only takes the number 4 would not have any inputs at all and may end up entirely constant (depending on what it does, of course).
It's then up to the caller to make sure the right variant is called. If you have strong types up the chain, this is easy and completely overhead-free -- they'll be compiled in their different versions, too. If you have a weaker type constraint (e.g. just any Number, rather than THE Number 4), then you'd do conditional dispatching at the call site.
For what it's worth, this is essentially how templates work in C++. It's also why compilation can take so damn long and can produce gigantic binaries, because when you have a function with 2 inputs of 4 different potential types each, you're up to 16 variants. Change that to 5 inputs of 4 different types and you're at 625 variants.
All that said, static compilation of TypeScript in its current form would be very difficult to make efficient, simply because JavaScript types in the abstract don't map nicely to hardware; Arrays can be extremely simple and linear or ungodly complex with holes and property overrides, and the 'right' thing to do with a Number is often different from the fast thing to do. That's why JITs are so valuable; they allow you to get around the ambiguity.
Edit to add: I should mention, it's possible you won't actually generate all combinations. You might know that certain combinations are impossible to hit due to other type constraints, or you might just know that they're unused (which leads to problems when you don't have the original function definitions to turn to; that's why C++ templates have to be in headers (I think that's true, at least? I might be wrong on that; I just use the magic, I don't understand it)).