Before, this would have involved replacing Babel with TypeScript for transpiling. This means projects could have slightly different results depending on whether they were using TypeScript or not, increasing the surface area for bugs and adding an extra step to the debugging process.
TypeScript support as its implemented in CRA just uses Babel like it did before, with some minor modifications such as also passing it .ts files. In parallel, it also runs the ForkTSChecker plugin for Webpack, which notifies you of type errors you made - however, it would work just the same if that plugin was not activated. Hence, there is far less divergence from regular CRA projects.
A way to think about it is to consider TypeScript to be a linter, like ESlint - but one that you can help by annotating your code with e.g. the types of values you expect it to get passed. Babel can now strip those annotations before it transpiles your code, but you still need TypeScript to do the actual "linting". See https://vincenttunru.com/TypeScript-vs-Javascript
If you set the build target to ES5 you can still use modern features like async/await and it will rewrite them using a regenerator function that runs on older platforms.
Like most metaphors, it's not a one-on-one match.
For example, you _could_ use TypeScript before with React Native. But it was convoluted: there were 3 different way to do it, none of them perfect, and all really brittle. But with Babel 7, you just add another transformer to your babel file and bam, it's treated as a first class citizen. It's literally a one line change.
tldr: This release meant that adopting TypeScript no longer meant buying into the entire TypeScript ecosystem and that we could keep using Babel to emit JavaScript. More importantly, this meant that we could actually use TypeScript as a type checker, and not so much as a "language" per se.
[1] https://davidgom.es/porting-30k-lines-of-code-from-flow-to-t...