10 ms·
Maybe it's just me, but TypeScript makes code hard to read. It's fine if the data model is kept somewhat "atomic" and devs are diligent about actually declarin
by CharlieDigital 2y ago
Maybe it's just me, but TypeScript makes code hard to read.
It's fine if the data model is kept somewhat "atomic" and devs are diligent about actually declaring and documenting types (on my own projects, I'm super diligent about this).
But once types start deriving from types using utility functions and then devs slack and fall back to type inference (because they skip an explicit type), it really starts to unravel because it's very hard to trace fields back to their origin in a _deep_ stack (like 4-5 levels of type indirection; some inferred, some explicit, some derived, some fields get aliased...).
type Dog = {
breed: string
size: "lg" | "md" | "sm"
// ...
}
type DogBreedAndSize = Pick<Dog, "breed" | "size">
function checkDogs(dogs: Dog[]) : DogBreedAndSize[] {
return dogs.map(d => /* ... */)
}
const checkedDoggos = checkDogs([])
Versus:
function checkDogs(dogs: Dog[]) {
// ...
}
Very subtle, but for large data models with deep call stacks, the latter is completely unusable and absolutely maddening.
- bluefirebrand 2y agoI agree that functions should probably specify their output type, MOSTLY to enforce that all paths that return from that function must adhere to that type I've seen plenty of regressions where someone added a new condition to a function and then returned a slightly different type than other branches did, and it broke things However, I don't think there is much value in putting types on variable declarations In your example, `const checkedDoggos = checkDogs([])` is good. Just let checkedDoggos inherit the type from the function I have a codebase I'm working on where the linter enforces `const checkedDoggos: DogBreedAndSize[] = checkDogs([])` It is very silly and doesn't add much value imo
- CharlieDigital 2y agoI want it on the other side (on the function return) so that it's consistently displayed in type hints and intellisense so I don't have to navigate the code backwards 3-4 layers to find the root type (do you see what I'm saying?) function checkDogs(dogs: Dog[]) : DogBreedAndSize[] { return dogs.map(d => /* ... */) } ^^^ That's where it's important to not skip the type def because then I can see the root type in the editor hints and I don't need to dig into the call stack (I know the end result is the same whether it's on the assignment side or the declaration side, but it feels like ensuring it's always on the declaration side is where the value is)
- dkdbejwi383 2y agoI'd prefer to have some type information over nothing if the choice were between TypeScript with some inferred return types, versus JavaScript where you're never really sure and constantly have to walk back up/down the stack and keep it in your mind.
- CharlieDigital 2y agoI'd say on backend, my preference is statically something like C#. Statically typed but enough type flexibility to be interesting (tuples, anonymous types, inferred types, etc)
- Sateeshm 2y agoMy policy is to type only when the typescript compiler yells at me.