In TypeScript, I was trying to get the type of the return value of a function. I naively tried:
type fnReturn = typeof myFunction();
Unfortunately, it didn't work, because that functionality isn't built into TypeScript yet. Bummer.
On the other hand:
const temp = myFunction(); type fnReturn = typeof temp;
This will work, but it's suboptimal. It calls
myFunction, and if
myFunction has side effects, this is pretty annoying. (Tsk tsk, writing functions with side effects!) Surely we can do better.
So I searched around and found a StackOverflow answer which suggested the following workaround:
const temp = false && myFunction(); type fnReturn = typeof temp;
Unfortunately, this was written back in the days of TypeScript 1.0. TypeScript has since added much more clever type inference. For example, TypeScript 2.0 is smart enough to determine that the type of
true && 6 is just
It goes deeper. Sure, if you say
let x = true && 6, it infers
x to be a
number. But if you say
const x = true && 6, TypeScript knows
x will never change - that's what
const means after all - so it infers the type of x to be not just any number, but the specific number 6! This is called a type literal. This is useful because then if you write something like
const y = x === 6 ? true : false it can statically determine that the type of
false. Keep this in mind for later.
This code used to work, but nowadays TypeScript is smart enough to statically determine that
false && myFunction() will short-circuit, and so the type of temp is (correctly, but frustratingly) determined to be the type literal
Not to be dissuaded, I tried something where TypeScript couldn't statically determine the type of the boolean:
let myBoolean: boolean = getFalseSomeObscureWay(); // type inferred to be boolean, not false. const temp = myBoolean && myFunction();
Now TypeScript infers the type of
temp to be... the union of
false and the return value of the function.
Darn it, TypeScript.
I mean, sigh, yes, you're right, as usual. If
false, then the type will be
false. If it's
true, the type will be the return value. So it's the union of false and the return value of the function. But that's not what I wanted! Argh. If only there was some way to make the boolean be false, but trick TypeScript into thinking it was true!
Hey, wait a minute...
What if I just...
const temp = (false as true) && myFunction();
It's beautiful, and it works. It casts the true value to have the type of the false literal. The type system trusts your cast and goes ahead to infer that the type of temp is just the return value of
myFunction. (You'd never lie to the type checker... right??) When the code is actually executed, the variable gets the value of false and doesn't call the function.
The crazy thing about this hack is that it can be extended to get the type of ANY arbitrary expression in TypeScript! e.g. in TypeScript there's no way to get the type of some arbitrarily deep nested access like
foo.bar.baz.blah, but of course now you can just do
const myType = (false as true) && foo.bar.baz.blah.
Addendum: arbitrarily deep nested type inference is coming to TypeScript! Someday. There's an issue for it, anyways.
As you may have noticed, I don't have comments on my blog. Instead, I do coffee-comments! Email me at firstname.lastname@example.org and ask to meet up for coffee and discussion. Coffee is on me for the first 5 emails that convert into meetups. :)