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.
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.
12 comments
[ 1.5 ms ] story [ 28.5 ms ] threadIt really should be called "vaguely typed script"
> 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
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.