I’m not joking. I prefer the after.
Edit: thanks. Yes, commas, not comments.
I’m not joking. I prefer the after.
Edit: thanks. Yes, commas, not comments.
I've worked on dynamically typed code-bases in the past, and also on code-bases without formatters like prettier... and I'm not going back there.
So many odd bugs can be avoided simply by taking a little bit of time and declaring some types. It doesn't have to be a super fancy type-system (I actually prefer if it isn't), but I really want to know whether something is expected to be a string or a number, or what properties an object can be expected to have, or what values a literal can accept, and so on. It's just so frustratingly time-consuming to figure out in hindsight. And all for some person's odd perception of simplicity.
Same for formatters - all the squabbling over some personal preferences on how code should be formatted. Hell no. Let's install some opinionated formatter and let it do its job, I want to tackle more interesting problems than yet another narrow-minded discussion about necessity of semicolons, placement of whitespace or line-length.
I'm at a point where I straight-up refuse to work with people who prefer to work that way; or at least require them to be a few departments away from me. They can be programming gods; if they can't be arsed to type their code so I can immediately grok it, they can program elsewhere.
I sometimes write TypeScript for 2 hours straight without actually running the code or any unit test, and it would just work -- the return value is exactly what you want. I don't think I can do that for JavaScript for more than 15 minutes even though they are the "same language".
Some of the codebases had tests, a good chunk of which could (and were) eliminated simply by using TSC as part of the build process. I think allowing the compiler and tooling like prettier to make choices for you leaves more space for you to think about the problem, not the myriad of problems _around_ it.
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.
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?
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.
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.
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
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.
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.
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).
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.
This one: https://github.com/hotwired/turbo/pull/971/files#r1317386731
> function buildFormData(formElement: HTMLFormElement, submitter?: HTMLElement): FormData {
> It might be useful to know that submitter is optional argument here.
> How would one express that? The variable now needs to be renamed?
And two lines later:
> const name = submitter?.getAttribute("name")
It's already easy to see that submitter is optional.
Why force yourself to read inside function implementations like this for every function you might use when fool-proof automated assistance is right there? What if the function was tens of lines long? What if the optional value only appeared inside a chain of 5 nested functions? How would you easily fix/update your code if the value isn't optional now but got changed to be optional in the future?
Manual effort like this is error-prone, not scalable, and a huge distraction. Why would avoiding type annotations be worth this?
Here's where whether or not it's defined can be traced to: https://github.com/hotwired/turbo/blob/41c074ff113a8882aadbc...
Maybe the types should have been written differently, to indicate that it's the type of the submitter property in a FormEvent. That's another cost of using TypeScript, is trying to get the types right. TMTOWTDI.
Why does that matter? Error-prone approaches create buggy code and we don't want buggy code, whether it's a library or something else. Libraries can be huge and complex, and arguably should have more robust edge case checking than regular code.
Let’s say you have some code :
const foo = {
x: 1,
y: 2,
};
and you want to add a field : const foo = {
x: 1,
y: 2,
z: 3,
};
Without trailing commas, the diff is - y: 2
+ y: 2,
+ z: 3
With trailing commas : + z: 3,
The second diff is actually much clearer at what’s happening.This is why it irritates me when people forget the trailing comma. It’s not a problem in the moment. But I know it will be a small but avoidable cognitive burden on the next PR (wait, why did "y" changed ? Oh, right, it didn’t).
All that, just to not have to add a trailing comma ?
Certainly the idea has been suggested many times. I think people end up formatting both before/after and doing a diff on formatted before against formatted after. I've done that.