You can always deserialize things as `serde_json::Value` instead of making types for everything to get similar behavior out of Rust.
Couldn’t that thing be typed as the web format? A nested set of string props with either string or number types in the leaves.
Then use those types to traverse and pull into «real» types?
I like to put structured data into structs in elixir too and the above is essentially what I would do in Elixir.
I don’t know rust well enough to see if I am missing some nuance
But then, you are basically throwing out your static type checks and just using it as a dynamic language, but with much more verbosity, cruft and additional ways to should yourself in the foot.
You also lose all of the performance benefits typing brings, and gain nothing in return. In JavaScript land, V8 moves heaven and earth to guess what your types are and optimistically compile your code behind the scenes assuming its type annotations are correct. Then it dynamically deoptimises and reoptimises at runtime with that new information, while your program runs. As well as being ugly, the equivalent “dynamically typed” rust program would have none of V8’s smarts. It would run dog slow compared to normal rust and still way slower than the (much cleaner) JavaScript equivalent.
Like wood, programming languages all have a grain. If you program in harmony with the language’s design, everything will seem easy. Compiler errors make sense. The standard library will seem useful and well designed. Program against the language’s design and you’ll hate every minute of it.
So then there’s more code for the language devs to write of course, but that’s just the cost of safety, which is highly desirable if you want the technology that you are building to be attractive for use in systems where correctness is critical, which also tend to be highly valuable. As a working professional it’s in my best economic interests to have such valuable tools in my skillset.
If you don't know what kind of data people give your function and you don't know what's supposed to happen, how can you write that function? I think many people use too strict of a type system. If your function works with any object that has a toString()->string function, then just write an in-line interface that defines it.
I actually love TypeScript here. It allows for `any` if you're prototyping, lazy or simply don't care. It allows mapped types, where the next dev can see how a type came into being - for example, Mutable<T>, Readonly<T>, Required<T>, Partial<T>. The names actually speak for themselves! And it eliminates the Java-style verbosity of creating classes and files all just for a type.
I'd prefer if dynamic languages would converge to gradual typing support, and static languages to gradual dynamic support. TypeScript is an example of the later, and PHP of the former.
Btw, the equivalent in Python (and MyPy/pyright) is object.
I tried at some point to use Rust for an API but then I depended on making calls to a very complex API. In JavaScript I would have just gotten back a complex object where I can then pick whatever I want progressively through object access methods. In Rust I ended up with more than 500 lines of type definition for the API and it still wasn't enough so I gave up. It is a bit extreme but when you work with an API from an ERP for instance you can get very very complex and extensive types that are not in your control and not very well specified.
Another good example is how complex all ORM internal code get once they try to add static typing. The typing in the ORMs code feels like black magic because they would really really need types as code but don't have it so have to rely on a bunch of crazy generic combinators.