It’s important to understand this fundamental limitation, because casting your incoming data, as suggested above, only works if you already know with certainty that your data has that “shape”.
In order to do your due diligence and actually examine your data as it enters your program to make sure there isn’t a mismatch between what you promised the program it would look like and how it actually looks, you need to run some logic over that data to inspect it. For anything more than a trivial interface with one or two values, you’re going to want to use a library, because it gets very complicated very quickly.
Some libraries that help you do that are:
Now these libraries are only useful if you know ahead of time what the shape of the data is that you’re expecting. If you wrote the api that the data is coming from, this is trivial, even more so if you wrote it in TypeScript, because you can simply import the same types. If you wrote the back end in a different (statically typed) language (C#/Go/Java), you can Google LanguageX to TypeScript type converter and find a program that will parse the source code and generate a TypeScript interface.
However, if the source of the data is not under your control and you’re not exactly sure what the shape of it is (but you know it’s complicated), you can use something like one of these programs to parse the JSON response from your api and generate a set of interfaces that describe it (you would do this part once during development, not each time the program runs).
You can then use the generated interfaces to feed into one of those runtime type-checking libraries I mentioned above. However, this too is fragile in that it will break if and when the api decides to change the shape of its data and you’ll have to do this process all over again.
For true certainty regarding the shape of your data coming from the server to your client application, you need to use GraphQL. This is one of the foundational reasons for its existence (but a little beyond the scope of this post). See here for further reading:
For a more in-depth discussion of what I outlined at the beginning of the post, see these articles (or just Google TypeScript runtime type checking):