The following code is trying to define the type of a function that's called with no arguments when its generic argument is undefined
, but with 1 argument for any other argument type. (There may well be better ways to accomplish this, which I'd love to see links to in the comments, but the question is about why Typescript works differently than I expected.)
When T extends undefined
is false, T
appears to turns into never
in the else branch, but only inside a function parameter list...
type OptionalArgBroken<Arg> = Arg extends undefined ?
() => void :
(arg: Arg) => void;
const suppressArgBroken:OptionalArgBroken<undefined> = function() { };
suppressArgBroken(); // Fine
const haveArgBroken:OptionalArgBroken<boolean> = function(b:boolean) { };
haveArgBroken(true); // Type error
As you can see on the Playground, the last line above gives the type error
Argument of type 'true' is not assignable to parameter of type 'never'.(2345)
After reading https://github.com/microsoft/TypeScript/issues/31751, I tried wrapping Arg
and undefined
in []
s, and that appears to have fixed the problem:
type OptionalArgWorks<Arg> = [Arg] extends [undefined] ?
() => void :
(arg: Arg) => void;
const suppressArgWorks:OptionalArgWorks<undefined> = function() { };
suppressArgWorks(); // Fine
const haveArgWorks:OptionalArgWorks<boolean> = function(b:boolean) { };
haveArgWorks(true); // Fine
Even though that fix worked, this is not the same problem:
type MakesSenseT = undefined extends undefined ? 'yes' : 'no'
const MakesSense:MakesSenseT = 'yes';
type ExtendsUndefined<T> = T extends undefined ? 'yes' : 'no'
const MakesSenseToo : ExtendsUndefined<undefined> = 'yes';
const MakesSenseThree : ExtendsUndefined<boolean> = 'no';
Why did my original code not work?