1. 11

  2. 8

    I don’t think I’m ever going to not hate Typescript. What’s worse is that I both feel it would most likely would keep things cleaner in the long run and it would help noobs get into my codebase more easily. It feels like a semi-enforced documentation step.

    But I hate it. I hate how it looks. I hate having a compiling step. I hate having to annotate everything. I hate how everyone thinks that you need it for modern development and that without it you’re coding in the stone ages. I hate that it’s really just suggesting types when I can just use any as void* which based on my aversion I almost always do whenever I’ve had to deal with it in the past. I even hate that the article’s author is using a ligature based font - and that one isn’t even fair.


    If someone started a project with it I could understand why. It really does make a lot of sense. But I’ll never use it of my own free will.

    1. 3

      Some people may have thought I wrote the above rant (including about the font). What I really dislike is how it’s treated as defacto. When I see a team implement Haskell on the back-end because they value types but also strictness in managing IO, no any, and ergonomics composition for a functional code base, then say “yup, TypeScript and fp-ts is good enough for our front-end”.

      1. 2

        I mean, TS with strict mode, noUncheckedIndexedAccess, plus all the ESLint rules that forbid any and all other unsafety is getting pretty close to Haskell in terms of type safety IMO.

        1. 2

          Out of curiosity, have you used Haskell professionally?

          1. 2

            No, although from what I gather from people who have, it’s used quite differently to Haskell in academic contexts. Much fewer weird tricks (lenses was the example they gave), and a willingness to accept IO in places where fundamentally it is necessary (e.g. managing application state shared across concurrency boundaries).

          2. 2

            Without an IO monad, do, and composition infix operators, it not close in ergonomics.

            1. 2

              Well, Promise is the equivalent of the IO monad, which makes async/await equivalent to do in that domain. Not having general monads for failure or immutable state is clunky though. Composition/infix can be emulated with “fluent” object interfaces.

              So yes, they’re obviously very different languages, but the point is that TS can be a very safe, expressive type system if you use it right.

              1. 1

                I’d disagree, not that your perspective of similarity is wrong, but because those differences matter a lot to me. Having seen a lot of libraries with .pipe(), et.al. all over the place, it’s very hard to read when you know the author would rather be in a language where this style is supported first-class. Comparing Promise isn’t great either: it’s not synchronous, it’s immediately evoked when constructed so many thunk it, canceling is a pain and rarely supported, and the error handling with reject and catch is a mess across libraries instead of branching Result or Either.

        2. 2

          Please note that I’ve used TS in many different contexts beyond your standard browser or node server and a portion of my frustration comes from trying to get TS running in atypical environments.

          For me TS is still frustrating with new projects. I’ve found that the configuration for getting a new TS project up and running with tests and build targets is very complex and fragile. The few times I’ve tried to start with TS I found it cost me so much time in setup that I would have been better off sticking with plain JS. In addition, I have encountered runtime errors multiple times despite compiling in strict mode and using as much typing as possible.

          Given this, I do think it does provide some minimal benefit around things like basic type and name errors being caught, that I think can be worthwhile for most projects to use.

          1. 2

            How much experience do you have with languages that require compilation? I ask, because my experience (not with Typescript, but in general) is that I tend to dislike dynamic languages (even though I love using Lua) because the types are so loose (I learned C early on in my career). I have a table in Lua, I have no idea what can be in it, whereas in C, I know because I can look up the structure definition.

            1. 1

              C++, Go, and Java. Java professionally. I dislike them all equally on the typing front. If anything it would be nice if types just magically sprung up after I’ve finished writing the rough draft of the code and had no enforcement until I’ve left the code base for a while. The thing is that while I’m in the code I know what I’m doing. It’s after I come back from working on something else I’m lost.

              1. 1

                Have you ever used languages with whole program type inference? (E.g., Haskell, F#) That might be what you are looking for.

          2. 1

            I see people writing out their types quite often when they don’t need to. Is there any particular reason not to do this:

            let state = {
              dirty: false,
              status: "foo",
              // Need the cast only if you want to
              // restrict the type of an empty generic collection
              data: <Array<string>> [],
            type State = typeof state;

            rather than this:

            type State = {
              dirty: boolean;
              status: string;
              data: string[];
            let state: State = {
              dirty: false,
              status: "",
              data: []


            1. 1

              I quite like this pattern, definitely great for incremental adoption.

              But I just find the casts for anything that isn’t inferable clunky, and while this is a fairly simple example, if the type of the collection is a more complex type (as opposed to just a string), doing all that inline can be a bit much. It’s just preference, but having them separate can be simpler for me. So usually if I have to annotate anything, I annotate everything.

              1. 1

                The reason I’ve seen is so you can add doc strings to the type itself and reference the type elsewhere. For example, what do you write for a function that accepts your State object?

                1. 1

                  You could add a docstring above the type State = type of state; line, right?

                  And you can import or reference or use the type the same as in the second example, as far as I know.