Created
July 24, 2024 22:43
-
-
Save duvallj/31dd269f5e28ec89841091fd88d4cd35 to your computer and use it in GitHub Desktop.
Typescript's Type Lattice Is Messed Up
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Playground URL: https://www.typescriptlang.org/play/?#code/MYewdgzgLgBFBOBDSBbArlApjAvDAPAIIA0MAQgHwAUiAXDAHLgNoA2riARq5kRQJT0mYFuy498lXBRgBvAFAwlMAPQqYAZSwAHGAEZ6AYXDR4aYLEQwABmEwA3TPGsx7iVmkyLloSLAAmIJgQTFAASphQaPBguDBU-NJyMADuABYAljzxCJ6JsgC+MAUA3N5Kapo6MABMRvCYiFgwAGZoYBYZ4HBpTTBoEME92LYOTi5uHpiknBgw4KwAnjAZLTaILoHBYADksJgAHhnQ5TC+0K4gGf4AEiDZeFTAnPQJSWQwAD6X14k4MgplECYA0ojEzpw3gB+KEwLYhEDhSLRMAJMpAgqnSpaTC6ADM9UazTe-x+-h6fUQFjQ7iWIORMQg62sp3OsFBKIghFefxk9iu5MevJgiHRymx1QALPQAOppJzYDKWdhnEAoIZQEAAc0i8vgADoYAAVTJM3rabSYSAwTiYYCIAaYWhY9QAKniwsIMEOWDA-iZJL5AvibQ6UC6sQ5MQyYC1Iti1kILntsVt-UG5MQTOs-OuLk4ywAVgNYBktWAQPAY3GoPL6WDYlBFpb+C6YO7A2TvQdff6Pe8vl2qG4q8hgIrYqHOt0o43m8FW0DKibjnCghBdrAUpWANapJVpEBzHH4mZ2h2Dea1pwpY7Ya8rMAtJwNcmdr3wmAV-Y9q1v4UfN8ub+Kcs5kncPBULOXL8GUmLyJUrD3PIbIiv4grxHQX5oCgtrwDM9BgDheHClYADUNplOc9yYPqSFajQ6FUAgyAQOgWBUAARDcmDsCApCcfwpAsagGCYFxMqVqw-gAISCfwsFAA | |
const transmute = <A, B>(a: NonNullable<A>): NonNullable<B> => { | |
// Step 1: Construct a `never` value | |
const doesNotReturn = () => { while (true) {} }; | |
// Step 2: Create function that uses the `never` value, but only if `a` doesn't exist | |
const voidHole = (cb: () => B | void) => { | |
return cb() ?? doesNotReturn(); | |
} | |
// Step 3: Create () => void that actually returns `a` | |
const returnsA: () => void = () => a; | |
// Step 4: Where it all comes together. This happens because: | |
// * () => A extends () => void (function returning an `A` can be used as `void` by just ignoring the return type) | |
// * () => void extends () => B | void (variance in function return types) | |
// This doesn't work without Step 3, because otherwise the inferred () => A does not extend () => B | void | |
return voidHole(returnsA); | |
} | |
// lol | |
const add = (a: number, b: number) => a + b; | |
console.log(add(transmute("Hello, "), transmute("World!"))); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment