Hacker Newsnew | past | comments | ask | show | jobs | submit | oslac's commentslogin

Is there still no type theoretic answer to unit testing? Does not the type or the class generally contain all the necessary information to unit test itself, assuming its a unit? That is, we should not have to even write these "theoretically". Just hit "compiler --unit_test <type>"


What you're describing is more or less fuzzing [1], at the unit level. I can't remember the names, but there are tools around that work like this at runtime (ie you define a test that executes functions from the test library that run tests based on input/output types and other user defined constraints).

There's almost always more business logic to what a unit should do than it's types though. Depending on the language, the type system can only encode so much of that logic.

Consider the opposite: can't the compiler generate implementations from types and interfaces? In most cases, no. LLMs are filling some of that gap though because they can use some surrounding context to return the high probability implementation (completion) from the interface or type definition.

[1] https://en.m.wikipedia.org/wiki/Fuzzing


Any number that cannot be effectively computed does not exist; there are actual hard physical limits to Numbers.


I disagree with your statement and provide Graham's number as a counterexample.

https://en.m.wikipedia.org/wiki/Graham%27s_number (edit: and TREE(3) )


They don't let you know this, but you can just delete your "I read this later" backlog. You're not going to finish it, or read any of it.


I tried a few, but (nearly) default Obsidian won me over by simplicity, ease-of-use.


It's also bad because you have to, as a programmer, actually type out the types a lot (compared to say, Ocaml, Haskell or Rust), and like you say, it makes it impossible to read.


Personally, I don't get much value out of TypeScript based on how I structure my code. I usually use 'any' types everywhere until my code is fully working and then, just before I open my PR, I have to painstakingly define types and replace all the 'any' references everywhere... Then whenever I get warnings while doing this, it's always related to me messing up the type definitions themselves and not related to my code. It feels like the type system is the error-prone part and my code is the reliable part... Should be the reverse; types are supposed to help me write my code but I find that it's my code (simple interfaces) which help me write my types.

Type annotation work is definitely the annoying part which slows me down and breaks my train of thought.

That said, I don't dislike TypeScript in theory as a language if used carefully. It may just be worth the annotation effort (kind of like how comments are usually worth the time they take to write). I just don't think it's worth the additional transpilation step and all the compatibility and source mapping issues that come with it.


>I usually use 'any' types everywhere until my code is fully working and then, just before I open my PR, I have to painstakingly define types and replace all the 'any' references everywhere.... It feels like the type system is the error-prone part and my code is the reliable part

This is akin to throwing water over an oil pan fire, then being frustrated at the water for your house burning down.

You need to either use the Typescript way throughout your dev process, or not use Typescript. Both of those options are valid, but you're currently doing half of both, resulting in unnecessary frustrations.


I disagree, my point is that my code is better if I write it as JavaScript. TypeScript is more like an extra unnecessary thing I need to do which doesn't add any value.

A better metaphor would be; I want to boil some chicken and I have a pan full of boiling water... Then just as I'm about to put the chicken inside, the head chef stops me and tells me that I need to pour oil into the pan.

I protest; "But sir, there's no need, the customer asked for boiled chicken, not fried chicken..."

"Do as I say" says the head chef.

So I reluctantly pour a tiny bit of oil on top of the water, then I add the chicken. It splashes around a bit, no big issues, and the chicken comes out OK.

The customer got the boiled chicken they ordered, and they're satisfied.

"See, it all worked out... Aren't you glad you listened to me?" says the head chef.


This metaphor is all wrong. If we're going to stretch cooking, TypeScript is the recipe book. While cooking it seems you would prefer to write "add a bit of something savoury", when you really mean "1 tbsp Worcestershire". TypeScript's greatest strength is in the next person being able to pick up the component and being able to run with it, or you being able to replicate it again in three months.

If you start by just throwing all the crap you want into a pot and afterwards try to remember what you added and how long you cooked it for of course it's going to be a lot of extra work. TypeScript requires a methodical approach which over the long run makes it easier for the entire kitchen.


In what ways would writing things the Typescript way make your code worse than the JavaScript way? I can't imagine the typing system preventing me from doing things that are better, other than cases where I want more expressive typing itself, which isn't even applicable to JavaScript.


Maybe your code is ok and understandable to you when you first write it, but when someone else has to work on it a month or two later, a lack of types makes it significantly more difficult.

It sounds like your process is a bit of a drag on you and I think you should improve it.


Completely valid - if you don't see value in a tool, don't use it.

But parent is saying that you should recognise that you're opting yourself in for a harder time by ignoring typescript at the beginning, and then trying to retrofit your way into type safety. That's definitely going to be more difficult and frustrating.

So either don't use typescript (which is fine fine - no one here cares about the programming language you use), or, use it 'properly' from the beginning and work with the tools you're using rather than against it.


If you replace axe with chainsaw, you can’t expect it will perform better if you keep the same workflow of smashing the thing into the tree. To get the advantages you have to adjust your workflow, otherwise it will of course feel like an obstruction.


It's not the same because maintainable JavaScript code essentially always converts to maintainable TypeScript code. Adding type annotations to existing JavaScript code won't make it harder to maintain. However, maintainable TypeScript code will not necessarily convert to maintainable JavaScript code after removing the type annotations... Yet as well as TS can hide the tech debt and delay repayment thereof, it's still tech debt and you still have to pay interest on it.

Anti-patterns are the same in JS and TS; tight coupling and low cohesion is bad, complex interfaces are bad, unclear separation of concerns is bad, poor encapsulation is bad.


Whenever I've faced this problem (usually converting legacy JS to TS), it's because the original code was structured in a complex or unique way. Sometimes it's unavoidable, but for most code, refactoring it to make it simpler and easier to read also simplified the typing for the code

So maybe, TS working as intended

Also depends on your TS config probably, but TS does a pretty good job with inference, so I find that I don't need to write that many type annotations, especially when assigning variables


I agree with that but the way I see it is that if your JS code is bad, then you may get value out of TS, but if your JS code is already good, you won't get any value out of TS.

TypeScript is like training wheels on a bike. All good if your priority is not to fall, but if you want to compete in the Olympics, you may have different priorities.

Also, I think starting with JavaScript and migrating to TypeScript leads to much better code than just starting with TypeScript. I think the reason is because if you start with JavaScript, you naturally tend to avoid architectural complexity because it can quickly become unmanageable. So then when you add type annotations to existing JS code, you're not adding extra architectural complexity; just adding types.

When you start directly with TypeScript, it allows you to reason about much more complex interfaces so there is more temptation to over-engineer architecturally. Devs feel more free to invent all sorts of unnecessary abstractions which will come back to bite them later.

Spaghetti code is spaghetti code; you can label each noodle but it's still spaghetti.


> ... the way I see it is that if your JS code is bad, then you may get value out of TS, but if your JS code is already good, you won't get any value out of TS.

You might not get any value from the typing when writing the code, but the poor sod tasked with maintaining it two years later definitely will.

Also, the added types and compile time check will greatly benefit anyone trying to perform all but the most trivial of code refactoring.

Typescript adds some inertia initially, and you are correct in that it will allow inexperienced developers getting away with writing overly complex code, but it's definitely worth it for any code base larger than a couple thousand LoC.


It also lets experienced developers who are inexperienced with the code base become productive faster. It's a boon for anyone who hasn't been there since the start.


I would argue that if you are writing a lot of ‘any’ types before writing types that you a very likely doing Typescript wrong. The vast majority of you code (if not 100%) should ideally be statically typed at any given moment, right from the start. This does not mean though that you need to manually specify types everywhere - you can rely heavily on type inference.


My view is that if you feel the need to define a type up front, it may be because you're overusing it; it's being referenced by too many different functions. This often indicates poor separation of concerns between components (low cohesion) and tight coupling.

Good abstraction would imply that you're dealing with a different, more abstract type as you move up the component/dependency hierarchy. If the same type (especially a complex type) is present at many layers in your code hierarchy, it often means that the abstraction is leaky.

A common issue I often see is when devs try to pass a Logger instance to all components and sub-components in their app... Instead, why not just make all the components emit events (or invoke some kind of listeners/callbacks), then handle and log all the events at the root of the code in one place? This is a lot more flexible because then you can use any off-the-shelf generic component and it doesn't need to know about the existence of your Logger.

Also, it's a lot easier to read and maintain code if all the logging is invoked in one place. Logging is a single concern, so ideally, it should only affect a single component/source file.


It sure helps to know that something is an object or an array and thus intellisense can actually do something useful for you before you run in the bowser, or what an API returns, or a parameter `users` to a function is an array of users vs a Set of users, or that the the field on a `User` type went from companyName to organizationName.

Typescript is going to help you out greatly there. Nothing about any of that will slow you down, in fact it'll do the opposite. If you're leaving those all as `any` until the last minute I think you're really leaving a lot of productivity on the table.


Prerequisites are mostly fake. You can just study what you need - depth first learning (assuming you are open to self-studying and this is not about academic bureaucracy)


This isn't a new phenomena, and does not differ at all from a normal non-tech person getting their information from Google Search. Hidden motivations for this push left as an exercise for the astute reader.


Mock has expectations about how the function is called. If you read a file from a disk, and you expect it only to be done once, a mock is "usable" in this scenario to count the number of invocations. Note that there aren't outside, observable, state changes or behavior involved in this. It is about the non-functional introspection.

Fake is just a simple implementation, like in-memory db to stand-in for a real one. In the optimal case, provided by library authors.


Coffee Nap is probably amongst the top 3 refreshing things I know of.


This always breaks my brain. From what I have read about sleep and the effects on caffeine on sleep, coffee nap seems to work in a very different way than just having coffee when you feel sleepy.

Some research suggests, it boosts your energy level as caffeine doesn't have to compete with adenosine (which make us sleepy)as by sleeping adenosine levels drop. But I always wondered how the boost works, when infact you could just have a nap and then drink coffee and the same thing should happen.

Anyway, I need to read more about this someday.


I discovered medicine naps as a child, and worked out caffeine naps when I got older.

Staying home if you’re sick is best, but if you have to get up and do something during the day, setting your alarm early, and taking whatever OTC medication you planned to manage your system, then going back to sleep for at least a half hour, means that the second time you wake up you don’t feel like you’ve been hit by a truck. It’s easier to get your ass out of bed and get ready for the day.


For public discussion, places like Zulip, Slack and Discord are fucking abysmal since they can hardly be googled and usually have stronger circle jerking in them.


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

Search: