[HN Gopher] Hyper Typing
       ___________________________________________________________________
        
       Hyper Typing
        
       Author : azhenley
       Score  : 35 points
       Date   : 2025-05-18 20:41 UTC (2 hours ago)
        
 (HTM) web link (pscanf.com)
 (TXT) w3m dump (pscanf.com)
        
       | pscanf wrote:
       | Author here. Curious to hear if anyone's experience also matches
       | mine, or if instead you find the trade-off to be worth it most of
       | the times. :)
        
         | agos wrote:
         | my experience absolutely matches yours. Navigating the types of
         | many libraries is often daunting (MUI, React-Aria, react-hook-
         | form to name a few)
        
         | matijs wrote:
         | Absolutely matches your experience!
         | 
         | Also curious about the delightful type generation Astro uses.
        
         | shirol wrote:
         | I don't use typing for correctness. I use it for documentation.
         | That's why I prefer JSDoc these days. I only type top-level
         | variables/functions to get hints from my editor. Everything
         | inside a function body remains untyped unless necessary. It's
         | the benefit of using Typescript without being forced to write
         | dumb code just to satisfy the compiler.
        
         | akdor1154 wrote:
         | Really nice write-up, thanks. The issues you raise with complex
         | typing are really nicely set out. It's such a trade-off, and
         | you're absolutely write to claim that sometimes, simplicity
         | trumps perfection.
        
         | gwking wrote:
         | I started using swift with a lot of enthusiasm for the type
         | system, but at times it was a huge time suck. There were lots
         | of obscure interface types that read like
         | BipartisanPoliticallyCorrectSequence<T> that made writing my
         | own generic utilities challenging. Documentation for that stuff
         | was very poor and the source code was often totally inscrutable
         | due to the implementation of core types in c++ and the overall
         | complexity of the compiler.
         | 
         | I recently saw Chris Lattner talk about Mojo and he made
         | passing reference to Swift trying to do too much with the type
         | system. It's telling that a guy with his experience is trying
         | something more like zig's comptime approach to types after two
         | decades of generics.
        
         | 6gvONxR4sf7o wrote:
         | I've felt the same, but I blame error messages and language
         | ergonomics rather than the practice itself. Basically,
         | everything you said, but with optimism that future languages
         | and language implementations make 'hyper typing' a good
         | practice. Recent languages have shown that there's a lot of
         | room for improvement on error messages in complex programs.
         | Hopefully that extends to complex types before too long.
        
         | p1necone wrote:
         | I certainly felt guilty reading it.
         | 
         | Having worked on large codebases with many developers of
         | varying levels of experience I have noticed that bugs that can
         | be written very often _will_ be written - a sort of programming
         | specific version of Murphy 's law. So I try to make the ones
         | that seem the most likely impossible. Sometimes I go too far.
        
       | omneity wrote:
       | > The strictness even allows us to remove the if check inside the
       | function, since now TypeScript gives us the compile-time
       | guarantee that obj will always have property key.
       | 
       | This is a dangerous suggestion. While the author does acknowledge
       | it is a compile-time guarantee only, that doesn't imply it is
       | safe to remove the if inside the function.
       | 
       | An API call, reading a file, calling less well-behaved libraries
       | or making some system calls can all result in objects that pass
       | compile-time checks but will cause a runtime exception or
       | unexpected behavior.
       | 
       | As for the thesis of TFA itself, it sounds quite reasonable. In
       | fact a high "level" of typing can give a false sense of security
       | as that doesn't necessarily translate automatically to more
       | stable applications.
        
         | jy14898 wrote:
         | > An API call, reading a file, calling less well-behaved
         | libraries or making some system calls can all result in objects
         | that pass compile-time checks but will cause a runtime
         | exception or unexpected behavior.
         | 
         | Seems crazy to me to have this attitude, the whole point of
         | typescript (and indeed many other languages with type checkers)
         | is that we can leave out unecessary checks if proven by the
         | compiler. The burden of compatibility is on the caller to
         | ensure they supply correct values
        
           | omneity wrote:
           | I don't systematically pick one or the other location for
           | these guards, but wouldn't it make more sense to have it in
           | one place, the function itself, both for DRY and to ensure it
           | being checked, rather than on every call site?
           | 
           | Such a requirement "oh yeah always guard your arguments for
           | calls against this function for the "same" thing your
           | compiler is doing anyway" shouldn't be implicit and
           | duplicated everywhere if it's always meant to be fulfilled.
        
             | jy14898 wrote:
             | I think I take the attitude that you parse/validate data as
             | soon as possible (ie when reading a file/coming from an
             | API), so that the rest of the code can rely on typechecks
             | alone.
             | 
             | That said, I come from a background where the language
             | doesn't let you consider that the type of a value might be
             | wrong (Haskell, for example), so perhaps I have more trust
             | than typescript deserves.
        
         | jfjfjtur wrote:
         | I think the point though was that practical solutions can be
         | imperfect, and spending complexity in an attempt at perfection
         | can lead to impractical solutions.
        
         | pjc50 wrote:
         | > An API call, reading a file, calling less well-behaved
         | libraries or making some system calls can all result in objects
         | that pass compile-time checks but will cause a runtime
         | exception or unexpected behavior.
         | 
         | Yeah, that is a design flaw that makes this kind of solution
         | less useful than it might be. C# has this problem with
         | "nullable": just because you've marked a type as not nullable
         | doesn't mean some part of the program can't sneak a null in
         | there. Haskell people wouldn't stand for that kind of nonsense.
        
         | Klaster_1 wrote:
         | > An API call, reading a file, calling less well-behaved
         | libraries or making some system calls can all result in objects
         | that pass compile-time checks but will cause a runtime
         | exception or unexpected behavior.
         | 
         | These all boil down to implicit `as` type casting parsed
         | boundary data into expected types. What you suggest is
         | replacing casts with to type narrowing guards, libraries like
         | Zod help with some of that. I think TS needs a special flag
         | where `JSON.parse` and alike default to `unknown` and force you
         | to type guard in runtime.
        
       | gnabgib wrote:
       | Small discussion, including post from author (19 points, 13 days
       | ago, 13 comments) https://news.ycombinator.com/item?id=43893127
        
         | dang wrote:
         | Thanks! That one didn't get much frontpage attention so maybe
         | we'll merge those comments hither.
         | 
         | (Note the merge process relativizes the timestamps on the
         | comments, so if you see confusing timestamps, that's why (https
         | ://hn.algolia.com/?dateRange=all&page=0&prefix=true&que...)
        
       | arcfour wrote:
       | I can definitely relate to this post. (And don't get me started
       | on those auto-generated SDKs in Typescript, eugh!)
       | 
       | I am far from an expert on type safety or JavaScript, so take
       | this with a large grain of salt, but for anything I write for me,
       | I like my simple JSDoc "typing" for that reason. It feels like
       | any time I introduce TypeScript into anything I'm doing, I now
       | have another problem. Or, more accurately, I spend more time
       | worrying about types than I do writing code that does things that
       | I find useful. And isn't the goal to save time and make
       | development easier? If not, then what's the point?
       | 
       | I should clarify I am not a developer by trade or education and I
       | am mostly doing things more closely related to systems
       | programming/automation/serverless cloud things as opposed to what
       | a lot of other people working with TS might be doing. So my
       | perspective might be a bit warped :-)
        
       | BarryGuff wrote:
       | Here I was thinking this was about someone typing at superhuman
       | speed. LOL!
        
       | skrebbel wrote:
       | I love the term "Hyper Typing" and I hope it becomes commonplace.
       | I've long been searching for a phrase with a similar to
       | "premature optimization" (with a similarly mildly-negative
       | connotation) but for overengineered type safety and I think this
       | is it.
        
       | Waterluvian wrote:
       | I've been absolutely loving template types and dot notation
       | pathing. I have an entire compile time (and therefore
       | autocompletable) argument for major.minor.patch.theme.schemaname
       | for all schemas in the program manage. I don't consider these
       | "hyper typing" because they're very, very easy to reason about
       | when used in the right context like dot notation paths.
       | 
       | I wish, however, I could cleanly type "this must be an integer
       | between 0 and 58" but typescript isn't that expressive unless you
       | do some pretty ridonkulous things. Especially with template
       | strings it would be so cool to have something like:
       | 
       | type foo = `v${0:1}.{0:99}.{0:}`
       | 
       | (or whatever pre-existing format exists elsewhere. I just made
       | that up)
       | 
       | This would be generalized as a "number range literal", maybe. So
       | not particular to template strings.
       | 
       | But not regex. Solving this with a regex literal type would be
       | the poster child of "hyper typing".
        
         | zdragnar wrote:
         | There are libraries that let you define refinement types[0] but
         | it does require a bit of runtime overhead, and the added
         | complexity depends on the library.
         | 
         | [0] https://zod.dev/?id=refine as an example
        
       | jasonthorsness wrote:
       | IMO it's great when libraries are fully typed: it's like
       | documentation you experience at the moment of use. I think what
       | the author is really dealing with at "when the library types are
       | so difficult to understand and use, I often end up resorting to
       | casting things as any, losing more type safety than I gained" is
       | more the API design being unwieldy rather than the typing itself.
       | You can fully-type a terrible API just as well as a great one and
       | the terrible API will still be a pain to use.
        
         | koito17 wrote:
         | I agree with this.
         | 
         | The error messages in TypeScript can be difficult to
         | understand. I often scroll to the very bottom of the error
         | message then read upward line-by-line until I find the exact
         | type mismatch. Even with super complex types, this has never
         | failed me; or at least I can't recall ever being confused by
         | the types in popular libraries like React Hook Form and
         | Tanstack Table.
         | 
         | Another thing I find strange in the article is the following
         | statement.                 I often end up resorting to casting
         | things as any [...]
         | 
         | Every TypeScript codebase I have worked with typically includes
         | a linter (Biome or ESLint) where explicit use of `any` is
         | prohibited. Additionally, when reviewing code, I also require
         | the writer to justify their usage of `as` over `satisfies`,
         | since `as` creates soundness holes in the type system.
         | 
         | Lastly, I wish the author had written a bit more about type
         | generation as an alternative. For instance, React Router --
         | when used as a framework -- automatically generates types in
         | order to implement things like type-safe links. In the React
         | Native world, there is a library called "React Navigation" that
         | can also provide type-safe links without needing to spawn a
         | separate process (and file watcher) that generates type
         | declarations. In my personal experience, I highly prefer the
         | approach of React Navigation, because the LSP server won't have
         | temporary hiccups when data is stale (i.e. the time between
         | regeneration and the LSP server's update cycle).
         | 
         | At the end of the day, the complexity of types stems directly
         | from modelling a highly dynamic language. Opting for "simpler"
         | or "dumber" types doesn't remove this complexity; it just
         | shifts errors from compile-time to runtime. The whole reason I
         | use TypeScript is to avoid doing that.
        
           | jasonthorsness wrote:
           | Yeah react router is neat in this regard I was confused then
           | pleased to see this the first time I used it
           | import type { Route } from "./+types/home";
           | 
           | Which lets me avoid a lot of manual typedefs
        
       | codr7 wrote:
       | At the peak of my hyper typing trip, doing lots of Haskell and
       | C++, I was trying to encode all the column/table/query types of
       | my database in the host language.
       | 
       | Nothing I would recommend, perfect doesn't mean its a good idea.
        
         | 8n4vidtmkvmk wrote:
         | Kysley does a good job of this. I haven't found it annoying.
         | 
         | Well... I think MySQL is a 2nd class citizen so I had to write
         | my own schema gen but that only burned a few hours. Now it's
         | great
        
       | sberens wrote:
       | I wish IDEs had more features/tooling around types. For example,
       | something like "expand all types by one level" where
       | 
       | { foo: Bar } would expand to { foo : { bar1: string, bar2: Baz }
       | } (and you could trigger it again to expand Baz)
       | 
       | (this would be especially nice if it worked with vscode/cursor
       | on-hover type definitions)
        
         | calderwoodra wrote:
         | The poor support for types in VS Code has always been a blocker
         | for me adopting it vs. Jetbrains, where types and the
         | intellisense are much easier to jump between.
        
       | nine_k wrote:
       | The examples of bad, overly complex types are indeed unpleasant
       | and unwieldy: colossal, highly nested types with long, cryptic
       | lists of type parameters.
       | 
       | I think this speaks of _lack_ of abstraction, not excess of it.
       | 
       | If your type has 17 type parameters, you likely did not abstract
       | away some part of it that can be efficiently split out. If your
       | type signature has 9 levels of parameter type nesting, you likely
       | forgot to factor out quite a bit of intermediate types which
       | could have their own descriptive names, useful elsewhere.
        
       ___________________________________________________________________
       (page generated 2025-05-18 23:00 UTC)