Hacker News new | ask | show | jobs
by tossandthrow 775 days ago
I 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?

2 comments

The 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.
The 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.
for 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.

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.

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.

> 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?

For 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.

1: You are similarly able to confirm yourself when you ducktype in TS, regardless: once you've ducktyped once in TS you are then at least helped by the compiler. Again, this is really not a good argument at all.

2: This is a programming practice I never see and would seriously question if its necessary ever, let alone "commonly". I think you may have picked up bad practices from writing in dynamic languages. Please see this for a few example arguments against this practice: https://softwareengineering.stackexchange.com/questions/1873...

3: You are now debating that Rust has better typing than TS, which makes sense because Rust is made from the ground up to have extremely well done static type checking, whereas typescript has to comply with dynamic typing originating from JS. It follows trivially that Rust has the better design because it has more freedom to do what it wants. JS < TS < Rust

I am curious on any example where changing type in scope is more performant or more readable.

it is not really an argument against typescript that Javascript is so bad that you need to spent time tracking your changes.

While in Rust I can assign string to foo and then update it with int

When do you need to do that? Can you give an example?

I suspect they're talking about shadowing. You can't change the type of an existing variable, but you can create a new variable with the same name but a different type.
You can use branded types for the first case.