Unconventional Ways to Cast in TypeScript

https://news.ycombinator.com/rss Hits: 5
Summary

I saw a post by qntm and remembered I had a playground with a similar idea. I then expanded that playground into a (probably non-exhaustive) list of ways to cast between arbitrary1 types in Typescript: Convention: The as Operator Ah, good ol' as: const cast = <A, B,>(a: A): B => a as unknown as B; We can't just directly do a as B because Typescript is smart enough to warn us about that, at least. That very same error message also says, If this was intentional, convert the expression to 'unknown' first. So we can just do that :3 If we were approaching this from a type theoretic perspective, it's already done & dusted, we have the most cut-and-dry demonstration of unsoundness, pack it up go home. But, what if we couldn't use as? Can we still get between two completely unrelated types? Unconvention 1: The is Operator is is commonly used for for interfacing with Typescript's flow-typing system, helping it figure out what exactly the return value of a boolean function means. For example: const notUndefined1 = <A,>(a: A | undefined): boolean => a !== undefined; const notUndefined2 = <A,>(a: A | undefined): a is A => a !== undefined; const maybeNumber0: number | undefined = someExternalFunction(); if (maybeNumber0 !== undefined) return; // Thanks to flow-typing, Typescript knows that `maybeNumber0: number` // if we get here. const maybeNumber1 = someExternalFunction(); if (notUndefined1(maybeNumber1)) return; // However, Typescript cannot infer flow from ordinary functions; // At this point, it still thinks `maybeNumber1: number | undefined` const maybeNumber2 = someExternalFunction(); if (notUndefined2(maybeNumber2)) return; // The `is` annotation has the exact same `boolean` value at runtime, // but provides extra information to the compiler, so Typescript can know // that `maybeNumber2: number` if we get here. However, is is sort of an escape hatch outside the regular typing system, and we can abuse it to tell the compiler whatever we want: const badDetector = <A, B,>(a...

First seen: 2025-10-23 17:32

Last seen: 2025-10-23 21:33