I agree that this is a different scenario. If you're able to have the client control the input to ensure only the correct types are passed in there may be some additional value there to keep things more sane.
However, how much of the data that you're dealing with in the client on the server and in the database are you really working with in the server itself? 1% of the variables? 2%?
Generally any heavy work will be handled in either the database itself or a background job just to reduce wait time for the client.
And if that's the case, you're spending the time defining types for the client, server and database, keeping them in sync, having to change them in each place and creating this exercise for the other 98-99% of variables passed in and out of your server just to gain the static benefit for the 1-2% where you're actually working with it in the server on the web request.
It's significantly more work with questionable benefits IMO.
This may be one of the differences of requirements that causes disagreement here. I can see how this might work if your app:
* Loads data from the client
* Later displays that data, unchanged, to the client
In that case, treating everything as a string is great, because you never need to use it as anything else.
In my case, I've never actually worked on an app that didn't need to do more than just display the data at some point. In those cases, I don't want to get everything as a string from the browser. My data is often not merely a string, and treating it as such means I have to deal with stupid questions like whether "0" == 0 == "null".
In my work, I have spent many, many hours repairing issues that could have been avoided if the client and server were both statically typed (and on the flip side, in services that are statically typed, rarely run into those same problems). I'm sure that this can be remedied by just "doing it better", but I'd rather operate from a foundation where doing it right is easier than doing it wrong.
Instead of strings, I want my apps to have a statically typed contract between the client and the server that specifies what endpoints are available and the data structures they accept and return. Ideally this is in a shared class/type definition file, but two definitions kept in sync can work as well if they don't share a language.
The common argument against statically typing your network requests at each end is that you're not resilient against unexpected values and/or version differences, but:
a) It's trivial to tell any JSON parser to ignore unknown values, so adding new optional fields to the request is never a problem.
b) If your app ever uses the data received from the client, version differences will eventually break your dynamic code, too. You'll just only be told so at runtime, potentially only after loading the bad data from the db.
If you ever use your app's data for anything other than rendering a template, you have to make breaking changes to your data structures very carefully, and using a strong layer of static types on both client and server helps to ensure that you consider all the breaking changes and either avoid them altogether or somehow mitigate them.