4 ms·
As anything - "it depends"™. I did not notice "every single line of code" getting better at all. Yes, it makes things easier on a large team where people do not
by julik 2y ago
As anything - "it depends"™. I did not notice "every single line of code" getting better at all. Yes, it makes things easier on a large team where people do not have time to do codebase discovery - or where people are moved to be highly interchangeable, on big codebases. Yes, static verification can help those teams and those codebases.
But it also introduces a lot of extra work "just to appease the type system". It rarely improves performance (if ever). Because TS has no runtime inference/validation, working with larger libraries or the browser can be a chore because half of your code are type signatures or casts.
So - not necessarily a naysayer, but I do believe that TS is oversold and with smaller teams/projects it might be slowing you down as opposed to helping.
- tossandthrow 2y agoI manage a relatively junior developer who has been using ts ignorer statements a couple of. times. I have said to him, that everytime he feel inclined to either use ts ignorer or do type coercion, he should call me first. every single time it is a reasoning flaw implementing a solution that is sub par and bug riddled. Had they just let types guide them, they would have become better developers and not had broken the application. I am curious though. can you provide a snippet where types would be a disprovement?
- julik 2y agoThe worst I had to deal with was converting anything browser-native into data structures that would satisfy the type checker (dealing with native references), and the whole "struct or class instance" dichotomy. Specifically - when there is a lot of DOM-native input (like drag&drop events and their targets and the targets of their targets) that have to be "repackaged" into a TS tree (ending up with properties which would be a JS-version of void*). An example of what I call "ceremony" would be interface BlockIndex { [key: string]: UploaderBlock; } const perServerId = {} as BlockIndex; uploaderFiles.map((fe) => fe.blocks.map((b) => b.serverId && (perServerId[b.serverId] = b))); While somewhat useful, this is in internal code which never gets used directly, and there are 4 lines of ceremony for 1 line of actual code.
- blainelewis1 2y agoThe ceremony is caused not by typescript but your misuse of map. You don’t need to create perserverid as an object first. Instead you could flatten fe.blocks, and then filter by b.serverId and then map to a key,value array and use Object.fromEntries to turn this into a keyed object. Something like: const perServerId = Object.fromEntries(uploaderFiles.flatMap(fe => fe.blocks).filter(b => Boolean(b.serverId)).map(b => [b.serverId,b])) And typescript infers the types correctly. But I still wouldn’t write it as one line, and I’d use lodash instead.
- tossandthrow 2y agofor most frameworks these typing are built. in (eg. react). my expectation is that there are some packages/DOM typings so you don't need to write them? regardless, your point stands: typing external dependencies is a pain.
- eddd-ddde 2y agoDuck typing can lead to a false sense of security when you /think/ you have Foo when in reality you have Bar with the same shape. Also Typescript sucks at keeping track of type changes in a single scope. While in Rust I can assign string to foo and then update it with int, I can't in Typescript. This leads to worse types or worse code for the same operation. Combined with typescript's lack of statements as values, conditionally initializing a value is pretty obtuse. Those are the issues that come to mind right now.
- mejutoco 2y agoYou can use branded types for the first case.
- vouwfietsman 2y ago> Duck typing can lead to a false sense of security when you /think/ you have Foo when in reality you have Bar with the same shape. This is literally always your problem with javascript, its only sometimes your problem with typescript. It's a weird argument. > Also Typescript sucks at keeping track of type changes in a single scope. Isn't this considered a very bad practice? Also rust does not allow this, it only allows shadowing. > Combined with typescript's lack of statements as values, conditionally initializing a value is pretty obtuse. Can you give an example?
- eddd-ddde 2y agoFor the first one: It's not an issue in JavaScript because there isn't some compiler telling me yeah that's fine, I have to confirm myself. For the second one: I know it is shadowing, what I mean is I find commonly that I'd like to have it in Typescript as well. In JavaScript is not necessary since I can just use the same variable. For the third one: If I have some string variable that needs to be created from either one set of instructions or another, in Rust I do exactly that: let foo = if x { ... } else { ... } In ts your options are making it mutable undefined and mutate it inside the if else, using a very weird unreadable ternary, using an IIFE that returns into the constant, or creating extra functions to move the logic out. None of these are even close in readability, locality, or soundness to the rust example. I find the _combination_ of those things that make it harder to write ts than js.
- louthy 2y agoSmall projects have a habit of getting bigger and small teams have a habit of growing also - usually to deal with the mess of the small project that is now bigger
- fhd2 2y agoIs that a bad thing? If you're building an MVP, do you really worry about how 2k developers are going to work on this 10 years from now? Requirements change and the code base needs to adjust with those requirements, that's gonna happen no matter what. I've met a lot of people trying to predict future requirements, deciding to overenginer today for a brighter future. I have very rarely seen anyone guess the future requirements accurately.
- louthy 2y agoSmall projects become bigger projects much faster than that! I’m not suggesting that anybody should think too far ahead when it comes to building mvps, but if it’s a choice between a typed language and a dynamic one like JavaScript, baking a poor decision in early is going to hurt later. And later is much sooner than you think. That’s not going to negatively affect your initial velocity, if it does, the team isn’t strong enough. If the project is just a one off website or something genuinely small, sure, who cares? Otherwise it's worth realising that you'll be dealing with the fallout of poor early decisions pretty quickly.
- julik 2y ago> That’s not going to negatively affect your initial velocity, if it does, the team isn’t strong enough. This. Note also that "a poor decision" might as well be "have developers fight the type system instead of delivering UI and pivoting if users don't like it".
- julik 2y agoThere are also cases where small teams that have grown grow unproportionally to the size of the product, and while the product is set up in a fairly sane way (and there is little wrong with it!) having 20 fresh people swarm into it destroys both the architecture and the execution. And with a small team enforcing cohesion for both of these is much easier! So a small project might as well stay small, but this should be somewhat a priority. Mythical man month in action.
- 946789987649 2y agoEven as a one person developer, you inevitably need to come back to old code and understand what's happening. Types help with that. The size of the team or codebase is irrelevant.