You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
inconsistency in type inference on union of function types #9104
//TYPE DOMAINtypeT1=(arg: string|number)=>string;typeT2=(arg: string)=>string;declarevarfn: T1|T2;varres=fn('x');// error TS2349: // Cannot invoke an expression // whose type lacks a call signature.// VALUE DOMAINconstf1=(arg: string|number)=>'x';constf2=(arg: string)=>'y';declarevara: boolean;constfn1=a ? f1 : f2constfn2=!a ? f2 : f1varres1=fn1('x');// Success, fn1 inferred as (arg: string|number) => stringvarres2=fn2('x');// Success, fn2 inferred as (arg: string) => string
Expected behavior:
Code in type domain at least should compile.
In both domains the correct type for the function should be (arg: string) => string and should not be dependent on the order of union members / conditional branches.
Actual behavior:
Code in type domain fails to compile with error TS2349: Cannot invoke an expression whose type lacks a call signature.
In value domain the type is dependent on the order of conditional branches
All incomatible primitive types should produce never when intersected.
However, unless --strictNullChecks is enabled, all primitive types are somewhat compatible, as: const X:string&number = undefined; is valid.
So when --strictNullChecks is enabled string&number = never, else string&number=undefined.
For the "real issue":
I propose UNION function types to work like that:
I know, the last could be seen to differ from how TypeScript handles function types in general, but it is closer to what ECMAScript allows:
var f1 = (A1) => {};
var f2 = (A1,A2) => {};
var b:boolean;
var f = b?f1:f2;
f1(1,2); // is valid ECMAScript
f(1,2); // is valid and commonly done ECMAScript
In TypeScript:
var f1 = (A1:number) => {};
var f2 = (A1:number,A2:number) => {};
var b:boolean;
var f = b?f1:f2;
f1(1,2); // fails (I love TypeScript for letting that fail)
f(1,2); // I propose this should not fail, even though the compiler identifies, that f could be f1 at runtime
I appreciate, that TypeScript requires the exact amount of parameters to be passed, but it shall be less picky in case of union function types. This allows us to simply run the method with two parameters - additional parameters are ignored if not required by the actual implementation.
For the Intersection function type it should be the same, except for the return type:
The "VALUE DOMAIN"-Example from the initial post works in TS 2.0.3 as described, but in my opinion it IS wrong, that it compiles. See the following example:
// VALUE DOMAIN
interface I1 {
X:number;
}
interface I2 {
Y:number;
}
const f1 = (arg: I1|I2) => {
};
const f2 = (arg: I1) => {
arg.X = 42;
};
var x:boolean = doSomeSomethingAndReturnBoolean();
const fn1 = x?f1:f2;
var res1 = fn1({Y:123}); // compiles, but at runtime fn1 = f2, which expects I1 as argument!!!
I expect, that the resulting fn1 can only be invoked with an I1 as argument, but not an I2, as it may be of type (arg:I1)=>void at runtime, which the compiler can detect with the rules described above.
Activity
Artazor commentedon Jun 12, 2016
It would be nice if
All incomatible primitive types should produce
neverwhen intersected.If
neverdetected in any input place it means type error.This behavior would allow expressing the following function union type:
thus
which allow assigning the correct type for the original issue.
Arnavion commentedon Jun 12, 2016
See #4612
RyanCavanaugh commentedon Oct 24, 2016
Duplicate #10025
0815fox commentedon Oct 25, 2016
For the "real issue":
I propose UNION function types to work like that:
In addition I propose:
I know, the last could be seen to differ from how TypeScript handles function types in general, but it is closer to what ECMAScript allows:
In TypeScript:
I appreciate, that TypeScript requires the exact amount of parameters to be passed, but it shall be less picky in case of union function types. This allows us to simply run the method with two parameters - additional parameters are ignored if not required by the actual implementation.
For the Intersection function type it should be the same, except for the return type:
The "VALUE DOMAIN"-Example from the initial post works in TS 2.0.3 as described, but in my opinion it IS wrong, that it compiles. See the following example:
I expect, that the resulting fn1 can only be invoked with an I1 as argument, but not an I2, as it may be of type (arg:I1)=>void at runtime, which the compiler can detect with the rules described above.