Hacker News new | ask | show | jobs
by hmsimha 1401 days ago
> In other words, I call bullshit on this entire blog post. Ignore it. Typescript is the correct solution. What is the alternative? Just using JS and letting things break without knowing it?

It seems like you and I read a different article. The post I read did not advocate for going back to JS; rather it advocated for better tooling and documentation (with examples, ideally) for library developers

    Conclusion
    I love typescript and think the team working on it are incredible. Typescript has completely changed the FE landscape and wouldn't want to dismiss its contributions.
    But as a library developer, we need:
    - better documentation,
    - better tooling, and
    - to spend less time making tsc happy.
    I shouldn't have to read the typescript compiler source code in order to figure out why it's resolving a piece of my code to a specific type.
I developed a library used by the React app I work on to cache network results in localstorage (to reduce the number of expensive requests made on page refreshes) and generate React-Query query-functions to read the result from localStorage first before fetching from the network as a fallback (if the data is stale or uncached).

It's not an especially large library, but I felt all of the pain points the author describes. It's great that you didn't with your library (and I'm sure there are large classes of libraries whose authors wouldn't feel these pain points), but it's a very real issue if your dealing heavily with generics, serialization/deserialization, and/or complex type interactions

3 comments

You answered your own question, learn how typing and generics work and you wouldn’t have had those issues.

The entire article persecuted TS because the author wanted to learn quicker with little effort. Writing TypeScript in a node, app or library makes no difference. It is a language, NOT a framework.

Yes, and a great way to do that is to read documentation, of which Typescript is frequently lacking. For example, I got a suggestion in the discord recently to use "generic parameter defaults" for a problem I was having, which were documented... in the release notes for Typescript 2.3... and no where else: https://www.typescriptlang.org/docs/handbook/release-notes/t...
I love Typescript but I just don’t think this is correct. Look at the Node documentation and then the Typescript documentation. The former tries to describe every behavior, the latter tries to give you a 101 in the feature. This is especially clear when it comes to the Deno and SWC teams’ attempts to reimplement tsc in a faster language - typescript doesn’t have a spec so they’re stuck looking at the tsc codebase to infer behavior.
I think you intended this as a reply to someone else. Or at least, it sounds like you're agreeing with me.
> Yes, and a great way to do that is to read documentation, of which Typescript is frequently lacking.

I completely disagree, and I was surprised by this sort of comment.

Find me a single programming language whose docs are as good as TypeScript's docs and reference. I'd be surprised if you could come up with a single example.

I think others have covered it here, but I want to point out that I actually think Typescript's docs are quite good for end-users! But, like the article here points out, lacking, for library authors.

There are lots of ways to do things that you kind of just have to learn from reading blog posts, or reading code and then asking in the discord when you see something undocumented (because have you tried googling "what does <T=...> in Typescript mean"?).

Ideally, at the very least, all syntactic features and keywords of the language should be documented, but it's more than that; Typescript is a metalanguage, and authors of many libraries have also developed patterns which are essential for describing complex types. Some of these patterns are documented (for example, discriminating union), and some are not (for example, opaque types). And some features which are documented could do with a lot more exposition and functional examples ("as const"), or notes on when to avoid (enum).

First hit for "Typescript equals in generic" is https://stackoverflow.com/questions/56843790/typescript-gene... which explains it. No search results in the docs, sure, but the very first hit for the first query I tried gave me the answer.
Whilst that's good, the TS documents should document this. Google searching and stackoverflow is not a valid replacement for actual documentation, IMO.
> because have you tried googling "what does <T=...> in Typescript mean"?

Search “typescript generics syntax” and you get the excellent TypeScript docs on generics as the first result. It covers generic constraints.

> It covers generic constraints.

Indeed, but I'm not sure how that's relevant since it doesn't cover generic parameter defaults.

C#, C++, Java (actually I am betting no one can beat that one)

I think you dismissed the actual issue he faced- gen type defaults, which I just looked is still not actually documented, it's just in the release notes.

Don't get me wrong, TS is my favorite language, but let's not gloss over things.

My career has been 95% c#.

Recently learning rust (spare time) and c++ for work. The documentation for these 2 are awesome!

PostgreSQL has great docs too

I think we are better at writing docs for programming languages than we are at libraries and frameworks. Maybe because languages are more ‘fixed’ and less likely to change so over time they just get better and better.

You picked two of the best documented projects around in Rust and PostgreSQL. I don't think that inferior documentation for libraries is a foregone conclusion. Rust's serde library is exceptionally well documented IMO.

It's a matter of having the skill and the will though, and I feel like a lot of projects simply don't emphasize documentation. Even so, not everyone's going to be a good technical writer.

> Find me a single programming language whose docs are as good as TypeScript's docs and reference.

This is a non sequitur. Typescript can be bad even if other languages are worse.

The argument being made in the article and this discussion isn't "use X instead of Typescript" it's "Typescript should be improved".

Is the argument "Typescript should be improved" or "We should allocate enough time/money from other things to improve Typescript"?

The former is vacuously true once you know it is an option. Everything would be better if it could be improved.

The latter is subject to questions about cost. If Typescript had best in its class docs, that would imply that other communities had failed to find or execute a practical option to turn time/money into docs improvements. That would be moderately persuasive evidence that Typescript's resources are better spent elsewhere.

---------

On an object level: Django and the python community tend to have great docs.

It could also be about refocusing within the Typescript project.
Golang has https://pkg.go.dev. Rust has https://docs.rs

Golang entire standard library is documented. Plus with how the language is designed docs don’t need to change with new versions. Just with new functions.

More importantly, golang has https://go.dev/ref/spec — most of the time I wished for better TypeScript documentation it's about syntax (though I did need to go read the default bundled libraries a couple times for details, that's rarer).
PHP used to have amazing documentation back in the days.

Everything spelled out. No "you must read the whole thing or have worked with it for years to understand page 5".

Plenty of inline examples and even more user submitted ones (although as with all user generated content, some caution should be used when reading those).

Have we used the same PHP? IME it's usually necessary to read the comments on the documentation for important information, which is frequently totally absent in the actual documentation.
Haven't used PHP seriously for a decade I think so I might have a bit of rose tinted glasses.

But I am fairly certain that like the Perl documentation and unlike Java and Spring docs none of them was infuriating.

JavaScript
Do you have an example? I've seen TypeScript handle crazy nested types (and generics) with ease.
Perhaps the React-Query source itself is a good example of when "simple" is still not "easy to read/write":

I picked out this file pretty arbitrarily: https://github.com/TanStack/query/blob/main/packages/react-q...

The author of react-query seems to be very clear at communicating how the library works and the library itself provides a great developer experience, but it's also an example of how much work can go into correct typing in library code.

I recently typed my state for zustand (react library for managing state) and it was a horrible experience.

An example from the docs with middleware:

https://docs.pmnd.rs/zustand/typescript#middleware-that-chan...

If anyone calls this “easy, just learn generics” I won’t believe them further.

Honestly, if that's what it takes to make something work with Typescript I'm surprised anyone uses it. I thought Scala/Cats was the only language/cult that indulged typism to this extent. **d save us from the static typing Spanish Inquisition and bring back dynamic languages.
Seeing one the worst implementation of static typing and then blaming static typing as a whole is unfair. gradual typing is just an abomination in practice as can be seen in both TS and Python. Maybe a language that's build from the start with gradual typing in mind can make it good but I doubt it. Static and dynamic typing are just at odds in general.
The types in Typescript are amazing. I believe they’re turing complete? The problem is that this allows people to do many really complicated things that’d just be avoided or impossible in other languages.

Typescript is a horrible as you make it.

We use Rematch/Redux for state management and typing it[1] was pretty easy.

I think it really depends.

[1] https://rematchjs.org/docs/getting-started/typescript

That is terrible. Good luck onboarding new developers or junior team members into your project.

I get playing with technology for side projects, but for something commercial there is no way I would sign off on including that package into a project.

Did you miss this example from the linked post about redux-toolkit? https://github.com/reduxjs/redux-toolkit/blob/4ab8c42cb20ae1...

This is what types look like when you're on the library side. The post made very clear they aren't talking about the app dev side. The library types are complex like this so that the app devs have a smoother experience.

Might help understanding if the author used ‘meaningful’ variable names…
It would be more understandable if you didn’t use single letter type names (someone posted an example from react-query elsewhere)
Those are some huge ternary ifs

I really wish Typescript had a great pattern matching system. It would be very nice indeed for structural typing, everything would be easier to read, probably some ways to add more power/expressivity, etc.

eg

    type GetOptions<T> =
      // Part 1: responsible for applying explicit type parameter to function arguments, if object { queryFnData: TQueryFnData, error: TError, data: TData }
      T extends {
        queryFnData: infer TQueryFnData
        error?: infer TError
        data: infer TData
      }
        ? UseQueryOptionsForUseQueries<TQueryFnData, TError, TData>
        : T extends { queryFnData: infer TQueryFnData; error?: infer TError }
        ? UseQueryOptionsForUseQueries<TQueryFnData, TError>
        : T extends { data: infer TData; error?: infer TError }
        ? UseQueryOptionsForUseQueries<unknown, TError, TData>
        : // Part 2: responsible for applying explicit type parameter to function arguments, if tuple [TQueryFnData, TError, TData]
        T extends [infer TQueryFnData, infer TError, infer TData]
        // ...
becomes

    type GetOptions<T> =
      // Part 1: responsible for applying explicit type parameter to function arguments, if object { queryFnData: TQueryFnData, error: TError, data: TData }
      T extends match { 
          { queryFnData: infer TQueryFnData, error?: infer TError, data: infer TData } => UseQueryOptionsForUseQueries<TQueryFnData, TError, TData>
          { queryFnData: infer TQueryFnData; error?: infer TError } => UseQueryOptionsForUseQueries<TQueryFnData, TError>,
          { data: infer TData; error?: infer TError }               => UseQueryOptionsForUseQueries<unknown, TError, TData>,
          [infer TQueryFnData, infer TError, infer TData]           => UseQueryOptionsForUseQueries<TQueryFnData, TError, TData>
          [infer TQueryFnData, infer TError]                        => UseQueryOptionsForUseQueries<TQueryFnData, TError>
          // ...
      }
or even, to make the top level way easy to understand in this case:

    type GetOptions<T> =
      T extends match { 
          Part1 => Part1Match
          Part2 => Part2Match
          Part3 => Part3Match
      }
where Part1Match etc are themselves pattern matches, so you can compose them like functions.
IME it's precisely the expressivity of nested types and generics and variations thereof that makes it hard for the library author.

The expressivity makes it possible for library authors have IntelliSense give more useful suggestions to the consumer, make automatic inference work in more places for the consumer, and make more illegal usage be impossible, at the expense of complicated type constructs. But of course all these is somewhat optional.

What library is this I was looking for a good cache to store network results quite recently?
It's not open-source or really polished for consumption. I did get permission to open-source it, but unfortunately didn't have the time to improve it to the point where it would be broadly useful.

In fact, now that https://tanstack.com/query/v4/docs/plugins/persistQueryClien... appears to be stable I'm thinking it might even be good to migrate to this (though it appears to require multiple queryclients if you want different cache parameters)