Skip to content

Instantly share code, notes, and snippets.

@duvallj
Created July 24, 2024 22:43
Show Gist options
  • Save duvallj/31dd269f5e28ec89841091fd88d4cd35 to your computer and use it in GitHub Desktop.
Save duvallj/31dd269f5e28ec89841091fd88d4cd35 to your computer and use it in GitHub Desktop.
Typescript's Type Lattice Is Messed Up
// 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