[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)