> it's sooo easy to write a React component taking in another component as a prop and some props for that other component ... but somehow lose the type safety of the props being passed in.
Previous comments interpreted this, I think, as "why don't I have type safety at runtime." Obviously, it's really little more than a very powerful static analyser on top of a superset of JavaScript. I'm not certain you were asking that; without a little more specifics to what you were trying to do or a code example, I'm not positive I'm understanding the issue you're describing correctly, but I think you're saying that in certain cases, with a React component where another React component is being passed as a parameter, along with other props, you can still reference the root component somewhere else with the wrong parameters and TypeScript doesn't complain.
Personally speaking, I have never written React without TypeScript in the last 3 years and have spent about half of my work time in that space. If you haven't taken a recent look and tried the scenario you describe in the latest version of the language, I'd suggest starting there. I remember, early on -- way prior to Hooks and the like -- we were looking at various tooling options around state management (react-redux/mobx/others) to use for a large project and ended up not choosing react-redux due to it being impossible/almost-impossible to get type safety in some cases[0].
Ninety-nine percent of the time when `tsc` fails to produce an error/indicate something useful to you in your IDE of choice like this, it's because implicit typing couldn't figure something important out and the project's configuration was set lax enough to quietly ignore it. One easy fix for me was to go full `strict`; disallow `any`. When typing can't be determined implicitly, you get a shiny error. This leads to the second thing that becomes necessary: providing types explicitly for functions/others -- in certain cases, sometimes because it doesn't work without it, sometimes just to have it clearly defined/obvious. Type aliases help a lot for drying things up and keeping the "type noise" to a minimum.
It's also possible that whatever tooling you're using to package/build things is interfering in some way (or publishing the result of the compile regardless of errors/warnings).
The strictest settings will bring a lot of new errors, and you'll probably be adding a lot of type info and adjusting code accordingly if you enable these in a project that was more lax, however, I've found it's usually worth it. The issues tend to also bring visibility to a really subtle bug or ... fifteen. Run the latest versions of TS -- improvements around this come constantly. And these days, support for TS on the library side is very solid[1].
Of course, it's still based on a dynamic language and has dynamic elements to it. It's always possible to violate the type system (heck, you can toss a comment in and violate it on a given line if you wish), but the problem you're describing I haven't remembered being a large source of grief, and most of the issues I used to run into from time to time aren't issues in recent versions.
If I misread your scenario, let me know; I've been pretty amazed at the kinds of things I can express with their type system and how well its compiler enforces those things[2] so I'm curious about where it really falls down.
[0] The specifics elude me, but I recall it had to do with the line that wrapped the component; this was three years ago and I had never re-examined the issue after that.
[1] Though I'd not encountered a component/library that I couldn't find a solid alternative to or workaround in some way to get it working in TS.
[2] It'd be nice if those extended in a manner that would handle things one encounters with Json data not quite matching up type-wise but a lot of that is because "it doesn't know how the object is going to be used/loaded at runtime" and you can't really expect it to do so.