4 ms·
I like the "why we do it" part in every section. Kudos to the author for that. However, the type guard section seems a bit off to me. Is the suggestion to chec
by izolate 6y ago
I like the "why we do it" part in every section. Kudos to the author for that.
However, the type guard section seems a bit off to me. Is the suggestion to check each and every property of `Product` in `isProduct`? Seems a bit verbose.
I tend to use Axios, which uses generics to set the payload return type (obviously, some trust in your API responses is needed here):
axios.get<Product[]>(...);
- sakarisson 6y agoI think the idea is that you validate the data once, on an API level. You don't need to validate the same data again after the initial inspection. In our team we use io-ts to validate all of our endpoints, but simple type guards could achieve the same goal. https://github.com/gcanti/io-ts https://github.com/gcanti/io-ts
- adriancooney 6y agoRuntypes is another excellent alternative. Highly recommend. https://github.com/pelotom/runtypes https://github.com/pelotom/runtypes
- Lunrtick 6y agoI've also been using Zod for the same purpose - they've got a nice comparison section that included io-ts https://github.com/colinhacks/zod#comparison https://github.com/colinhacks/zod#comparison
- agloeregrets 6y agoThe word in the back of my head wasn't Verbose. It was `Expensive`. Explicit looping and checking values like that seems like the answer to 'why is our app slow'.
- bwestergard 6y agoThe latency will be linear with the size of the JSON payload, and the constants will be tiny.
- horsawlarway 6y agoI mostly disagree with you here. Checking for the existence of a key on an object is dirt cheap. Even if you happen to have a case where it is expensive, there's absolutely nothing that says your typeguard has to take that approach. I've seen some reasonably sane code that just checks that the 'Type' field of the object matches the expected value, and the 'Version' field is the right number. It's not going to catch all the possible errors there if someone breaks the api contract, but it's a lot better than a raw cast.
- eat_veggies 6y agoYou'd only do this once, at the point data is going into your app via e.g. a network request. Data from the network is an untyped blob, and all your TypeScript efforts fall apart if that blob doesn't match your expectations (which are encoded in your types). In most cases it's worth it to trade the small performance penalty for correctness, especially since the cost of fetching data is already dominated by the network and backend.
- Normal_gaussian 6y agoIndeed. I have recently been benching an ingestion pipeline (minor data mangling, then chuck into the db), and considered switching the exhaustive type checking off, or at least making it probabilistic. However profiling showed that less than 3% of cpu was spent on this validation, making it worth every cycle. Tbh the bench here suggests the only non algo perf worth doing would be switching to rust with pre allocated memory for each request. By the time we are up to the scale where the sin le digit gains are worth it we'll have more than enough capability for going straight to the software end zone.
- horsawlarway 6y agoTo me - A type guard lets me be as picky as I'd like to be in the given circumstance. I also use axios, and I also take advantage of the generics you've shown above, but I acknowledge that I'm essentially just saying "Trust me" and doing a cast when I do that. And I'll add - that exact style of code has been a source of bugs in our production codebase before. A dev will pick the wrong type for the axios generic, and if the api response happens to overlap on the used fields, no one notices. Then it blows up 6 months later when someone tries to access a field on the defined type that wasn't actually returned in the api response.
- lhorie 6y ago> And I'll add - that exact style of code has been a source of bugs in our production codebase before. Very much this. That scenario will break if e.g. the backend API changes. This is a constant source of frustration for someone I know, whose backend team has a habit of not communicating their changes to the frontend team. There's nothing TS can do to enforce that the actual type of the response matches what the type declaration says (hence the need for runtime checks in this case).
- seer 6y agoIf the api has some contract with it OpenApi / Swagger / etc, its surprisingly easy to write a parser that would convert those to typescript types. TS has an awesome use as a library itself where you can write the ast with, and then tell it to convert it to code. We use it to great effect ourselves, by generating types for axios. https://github.com/ovotech/laminar/tree/main/packages/laminar-cli#axios-type-generation https://github.com/ovotech/laminar/tree/main/packages/lamina... Now granted, you’re now trusting the api writers with their contract, but if its another team in the org we’ve found it to be warranted.
- lucasyvas 6y agoI believe this to be entirely sufficient as well, despite not being truly safe. It's either going to throw an error immediately or on first bad access. It makes no difference to me. I can see how the proposed solution could be "better", but I'd rather avoid the validation code and instead get the type right.