Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> I’m not joking. I prefer the after.

Everyone likes the simplicity that comes with removing guardrails, but when easily preventable problems happen that's glanced over as an unavoidable fact of life.



> but when easily preventable problems happen

easily preventable is doing a lot of work here. This is assuming the types are already written and never need to be maintained. How often does the type checker catch a problem with the code vs the type definitions themselves?


> How often does the type checker catch a problem with the code vs the type definitions themselves?

All the time? I've worked on code bases with multiple people without types, and whenever there's a place that can produce e.g. "string or undefined" like when a key might not be found in a collection, it produces edge cases everywhere that don't get noticed outside of the happy path, including after the code has been merged. You're forced to simulate in your head all the code paths, and remember which values might be optional which is error-prone, isn't scalable and eats up brain cycles.

Even typos like `object.detail.name` vs `object.details.name` cause runtime errors, or calling a function with the wrong number of arguments or in the wrong order, some of the most trivial bugs you can think of.

I don't understand how someone can dislike writing type annotations so much that they're happy having their time wasted like this when automated assistance is right there. To me, it's like not wanting to use a spellchecker when writing an article, or opting out of syntax checking code before it's ran.

I get that problems with type definitions can be frustrating but it's better than runtime errors (having to write more tests isn't better either), and often flags actual bugs, potential future bugs ("what if this was undefined sometimes?"), or overly dynamic code that's hard to reason about (e.g. conditionally adding/removing fields from objects, or having a field that changes type between string/array/undefined vs using an array of strings instead). I'd love a counter example here - often the examples I see has overly dynamic code because the coder hasn't had a strong incentive to avoid such code before. As in, I write type checker friendly code so I can benefit from type checking.

90% of type annotation stuff I work with is mundane and simple (e.g. strings, numbers, arrays, something optional, object with basic fields) and is well worth the minimal effort. The more complex stuff isn't needed often, usually optional, and gives you protection from tricky bugs too.


> Even typos like `object.detail.name` vs `object.details.name` cause runtime errors, or calling a function with the wrong number of arguments or in the wrong order, some of the most trivial bugs you can think of.

In Clojure, a dynamically typed language, referencing a var that is not declared, or calling a function with the wrong number of arguments will result in a compilation error. You don't need static typing or type annotations for this.

> I don't understand how someone can dislike writing type annotations so much that they're happy having their time wasted like this when automated assistance is right there. To me, it's like not wanting to use a spellchecker when writing an article, or opting out of syntax checking code before it's ran.

It's not about liking or disliking, it's about "wasting time." Spell checking and syntax checking are free, annotating everything with types and maintaining them is not.


> In Clojure, a dynamically typed language, referencing a var that is not declared, or calling a function with the wrong number of arguments will result in a compilation error. You don't need static typing or type annotations for this.

Can it catch problems like e.g. if you try to access a `y` field on some input object but only field `x` is defined? And if you want to define a function that takes a callback that must accept two arguments? What about ways to force you to check a variable with type `string | undefined` is defined before you do something with it? At some point it must breakdown because more complex checks can't be inferred?

> it's about "wasting time." ... annotating everything with types and maintaining them is not.

See this example. I'd argue the type annotations are minimal, but you gain a lot of safety, documentation and refactoring help from them: https://github.com/hotwired/turbo/pull/971/files


The arity check in clojure sounds like a nice balance between runtime and compile time errors.

Having runtime errors is the point - that's real dynamic typing for you. If not for the possibility of runtime errors, you'd have to do more to have the code run. A lot of junior devs who prefer static typing don't get it. Senior devs who prefer static typing at least understand that some have a different preference. Of course you don't want a lot of runtime errors to make it to production, but in development, yes.

There are those who think that the IDE should provide feedback at every keystroke. Most IDEs have this opinion built into them. But I don't like it very much. It's gotten to the point where there isn't an IDE I really like. I miss Atom.


> To me, it's like not wanting to use a spellchecker when writing an article

Huh, I'm absolutely in the pro-static-types camp, but I never use spellcheck which I personally find distracting and unhelpful. I wouldn't consider those two be similar issues at all.


> I'm absolutely in the pro-static-types camp

Reflecting on your comments on the Transcendental Syntax threads, you should really look into linear logic, or at least System F (https://en.wikipedia.org/wiki/System_F).


Definitely will at some point


me too!


> easily preventable is doing a lot of work here.

It isn't. It's the most basic value proposition of TypeScript.

> This is assuming the types are already written and never need to be maintained.

No, it doesn't.

You need to write software so that you get an application that does what you wish it to do. Does this surprise you? This is not something that was invented by TypeScript.

When a software developer wants to prevent bugs when adding features, what they do is add preconditions and post-conditions to enforce invariants, and they handle code paths specific to both the happy path and failure modes. What static typing does is ensure these checks can be done at compile time, and that failure modes can be prevented by ensuring data types that do not meet conditions cannot be passed to functions.

TypeScript allows developers to check preconditions and post-conditions by defining types and adding type assertions that verifies whether an object is of a certain type, and then assert at compile-time if they meet preconditions and post-conditions. If they specify a type that has specific characteristics, the typescript compiler helps them by automatically checking preconditions and post-conditions, and prevent code paths that are proven to be failure-prone.

This is the very basic of software development. This can only be interpreted as "maintenance" or "extra work" by someone who thinks it's ok if the program crashes and malfunctions if preventable failure modes are not prevented. This is not a trait of a programming language. This is a trait of your and the level of quality at which you do your job.




Consider applying for YC's Winter 2027 batch! Applications are open till November 2.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: