But most system also ingest external data -- that data truly is "unknown" until you parse/validate it. Once you do parse/validate it, you're going to want it to have the correct type.
You shouldn't "never" use. You should only use it in limited, constrained ways, and always with other controls that are sufficient to ensure it's correct.
If you have complex types, it's sometimes the easiest way to do what you want, and it's perfectly safe as long as you are 100% sure that the types are compatible.
For example, where you have a fluent-style API where each method modifies the types it's unavoidable to end up using that kind of cast
It’s not even safe if you’re 100% sure the types are compatible, unless you’re also 100% sure nothing will change that fact. The reason it’s unsafe is because it suppresses the type error permanently, even if whatever factors led to your certainty now change anywhere upstream ever.
There are certainly ways to guard against that, but most of them involve some amount of accepting that the type checker produces errors for a reason.
Yes of course the types could change in the future, and the forced cast might cause issues. I wish there was a better way, but this is an acceptable tradeoff.
Bear in mind, most changes that could cause issues will still be caught by the type checker in whatever object you're casting to. Obviously it should not be overused where not needed, but it's almost always used in fluent apis because there's no better way (that I know of, at least)
The `return this as any` there, which effectively casts it to the same type this had, but with the added get route is perfectly safe, it works, and will never be a problem by itself.
It’s funny because the reason you used a language like typescript is because you want the compiler to be 100% sure that it’s compatible, not relying on human reasoning.
If you were going to rely on that anyway, why not just use JavaScript as is and avoid the boilerplate from typescript
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.
Er, my justification was that the code in question was meant to be minimally demonstrating someFn, and adding an import or a verbose type seemed to distract from that a little.
But mostly it just gave me a chuckle. I tried it because it seemed logical, but I didn't really think it was going to work until it did..
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.
it's gradually and structurally typed and I think that's what makes it great. I also disagree that it's vague. Nowadays you can even have typesafe regex
This post is trying to solve a problem you should never have to solve. The function in the post:
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
> should never be used in a professional codebase
Mostly true.
But most system also ingest external data -- that data truly is "unknown" until you parse/validate it. Once you do parse/validate it, you're going to want it to have the correct type.
You shouldn't "never" use. You should only use it in limited, constrained ways, and always with other controls that are sufficient to ensure it's correct.
Eh it's ok to use `as unknown as X` sometimes
If you have complex types, it's sometimes the easiest way to do what you want, and it's perfectly safe as long as you are 100% sure that the types are compatible.
For example, where you have a fluent-style API where each method modifies the types it's unavoidable to end up using that kind of cast
It’s not even safe if you’re 100% sure the types are compatible, unless you’re also 100% sure nothing will change that fact. The reason it’s unsafe is because it suppresses the type error permanently, even if whatever factors led to your certainty now change anywhere upstream ever.
There are certainly ways to guard against that, but most of them involve some amount of accepting that the type checker produces errors for a reason.
Yes of course the types could change in the future, and the forced cast might cause issues. I wish there was a better way, but this is an acceptable tradeoff.
Bear in mind, most changes that could cause issues will still be caught by the type checker in whatever object you're casting to. Obviously it should not be overused where not needed, but it's almost always used in fluent apis because there's no better way (that I know of, at least)
> it's perfectly safe as long as you are 100% sure
That was funny to read
If you disagree, you're welcome to prove me wrong!
To give you an example from a popular open source ts-heavy project:
https://github.com/elysiajs/elysia/blob/94abb3c95e53e2a77078...
The `return this as any` there, which effectively casts it to the same type this had, but with the added get route is perfectly safe, it works, and will never be a problem by itself.
It’s funny because the reason you used a language like typescript is because you want the compiler to be 100% sure that it’s compatible, not relying on human reasoning.
If you were going to rely on that anyway, why not just use JavaScript as is and avoid the boilerplate from typescript
The code I linked for example results in a web router that is fully type safe.
It's not like using js at all, not that I think there's anything wrong with it, if that's your jam.
This is a great example of "letting perfect be the enemy of good enough".
Typescript is "good enough" at it's job. That's a great reason to use it.
Funny, just yesterday I found myself casting in a way I'd never seen before:
This wound up being useful in a situation that boiled down to: 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.Why not use annotation instead?
Didn't occur to me, that's certainly more defensible! Though maybe less humorous.
Or: cons foo = [‘foo’] as const;
> In a case like that `as const` doesn't work, since the function doesn't expect a readonly argument.
I don’t get this? why do I need to say as const?
`as const` is a special annotation that lets the TypeScript compiler infers the more specific type `["foo"]` instead of `string[]`.
I generally put lint rules to prevent casting, why cast here instead of declaring `props: (keyof SomeObj)[]` or `props: Parameters<typeof someFn>[0]`?
Er, my justification was that the code in question was meant to be minimally demonstrating someFn, and adding an import or a verbose type seemed to distract from that a little.
But mostly it just gave me a chuckle. I tried it because it seemed logical, but I didn't really think it was going to work until it did..
You could also do
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.
Can't you change settings in ts to make it more 'strict' than this ?
Surprised the `satisfies` operator wasn't called out
This why I find Typescript frustrating.
It really should be called "vaguely typed script"
it's gradually and structurally typed and I think that's what makes it great. I also disagree that it's vague. Nowadays you can even have typesafe regex
TypeScript is incredibly safe if you use strict tsc settings and ts-eslint strict presets.
If it were this strict out-of-the-box, it probably would have been hated since most devs don't really want to deal with static typing.
https://typescript-eslint.io/getting-started/typed-linting
On the other hand, you can run Doom in TypeScript's type system.