12 comments

[ 1.5 ms ] story [ 28.5 ms ] thread
Sigh, the abuse of void was particularly eye-opening for me. If one really must do this - and I can think of a couple of cases where one might mostly around progressively porting old codebases to typescript - I'd strongly prefer the simple `a as unknown as B;` as one can easily grep for ` as unknown as ` to find your crimes.
Funny, just yesterday I found myself casting in a way I'd never seen before:

    const arr = ['foo'] as ['foo']
This wound up being useful in a situation that boiled down to:

    type SomeObj = { foo: string, bar: string }
    export const someFn = (props: (keyof SomeObj)[]) => {}

    // elsewhere
    const props = ['foo'] as ['foo']
    someFn(props)
In a case like that `as const` doesn't work, since the function doesn't expect a readonly argument. Of course there are several other ways to do it, but in my case the call site didn't currently import the SomeObj type, so casting "X as X" seemed like the simplest fix.
(comment deleted)
Surprised the `satisfies` operator wasn't called out
This why I find Typescript frustrating.

It really should be called "vaguely typed script"

I'd call it an "actually usefully typed script for people without a stick up their butt" but that's a mouthful. TypeScript will do.
This post is trying to solve a problem you should never have to solve. The function in the post:

  const cast = <A, B,>(a: A): B => a as unknown as B;
should never be used in a professional codebase. The post even admits (though, in my opinion, understates) as much:

> If you're holding it right, these things don't come up, and your code genuinely is much much safer than if you used raw Javascript.

Just wanted to highlight this point I feel needs to be underscored

Isn't the post more about the interesting capabilities of the language rather than an engineering context?
Can't you change settings in ts to make it more 'strict' than this ?
I think the title undersold it. I would call it "a nonexhaustive set of abuses of casting in TypeScript"

I actually thought that calling out the `is` operator was useful, I have a generic utility method I call `filterFalsy` which takes `T | undefined | null` and returns `arg is T`, which seems decently safe, but it's interesting how it would fail when asserting between two types.

Unconvention 2 made me vomit, inlining a function like that would never pass code review, indeed if you remove the mutator from being declared inline it restores type soundness as you would expect

Unconvention 3 is important to learn, TS "duck typing" is not resilient to usage of spread/Object.(keys|values|entries)

Unconvention 4 is why I argue to use `callback: () => unknown` whenever you won't use the return type, it is the least restrictive and also implies to stay the hell away from that return value.

Fun article.

Another one:

  const cast: <A, B> (a: A) => B = function <B> (): B {
    return arguments[0]
  }
  const n: string = cast(1)