A big problem we've hit with allowing users to write Typescript (or any other general-purpose programming language) for our product is that it's too powerful.
Observationally, it seems that all that power eventually gets used, and then you end up with config that has complex interfaces, or becomes non-portable because it's doing arbitrary file reads, or is non-deterministic because of an ill-advised call to random or the system clock. The config then becomes something not maintainable by the rest of the team - just the few who know it.
Config languages seem to need to strike an interesting balance between being complex enough to allow for reasonable DRY code (which helps maintainability at the expense of readability), but not so complex that they're not generally-maintainable.
Yep, application code can have the same problem! The difference is that application code lives "inside the abstraction" of the program, and is viewed and edited by a much smaller set of developers.
Configuration, by contrast, sits at the seam between two systems. It's the top-level parameterization of the abstraction, and behaves more like an API. E.g. imagine if the only way to configure Kubernetes or Docker were in language-specitic bindings - there was no such thing as a YAML lingua franca.
Observationally, it seems that all that power eventually gets used, and then you end up with config that has complex interfaces, or becomes non-portable because it's doing arbitrary file reads, or is non-deterministic because of an ill-advised call to random or the system clock. The config then becomes something not maintainable by the rest of the team - just the few who know it.
Config languages seem to need to strike an interesting balance between being complex enough to allow for reasonable DRY code (which helps maintainability at the expense of readability), but not so complex that they're not generally-maintainable.