Merge pull request #4200 from Microsoft/unionPartialSignatures

Partial matches in union type signatures
This commit is contained in:
Anders Hejlsberg
2015-08-13 23:16:48 -07:00
29 changed files with 2735 additions and 547 deletions
+56 -43
View File
@@ -3131,52 +3131,66 @@ namespace ts {
setObjectTypeMembers(type, members, arrayType.callSignatures, arrayType.constructSignatures, arrayType.stringIndexType, arrayType.numberIndexType);
}
function findMatchingSignature(signature: Signature, signatureList: Signature[]): Signature {
for (let s of signatureList) {
// Only signatures with no type parameters may differ in return types
if (compareSignatures(signature, s, /*compareReturnTypes*/ !!signature.typeParameters, compareTypes)) {
function findMatchingSignature(signatureList: Signature[], signature: Signature, partialMatch: boolean, ignoreReturnTypes: boolean): Signature {
for (let s of signatureList) {
if (compareSignatures(s, signature, partialMatch, ignoreReturnTypes, compareTypes)) {
return s;
}
}
}
function findMatchingSignatures(signature: Signature, signatureLists: Signature[][]): Signature[] {
function findMatchingSignatures(signatureLists: Signature[][], signature: Signature, listIndex: number): Signature[] {
if (signature.typeParameters) {
// We require an exact match for generic signatures, so we only return signatures from the first
// signature list and only if they have exact matches in the other signature lists.
if (listIndex > 0) {
return undefined;
}
for (let i = 1; i < signatureLists.length; i++) {
if (!findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ false)) {
return undefined;
}
}
return [signature];
}
let result: Signature[] = undefined;
for (let i = 1; i < signatureLists.length; i++) {
let match = findMatchingSignature(signature, signatureLists[i]);
for (let i = 0; i < signatureLists.length; i++) {
// Allow matching non-generic signatures to have excess parameters and different return types
let match = i === listIndex ? signature : findMatchingSignature(signatureLists[i], signature, /*partialMatch*/ true, /*ignoreReturnTypes*/ true);
if (!match) {
return undefined;
}
if (!result) {
result = [signature];
}
if (match !== signature) {
result.push(match);
if (!contains(result, match)) {
(result || (result = [])).push(match);
}
}
return result;
}
// The signatures of a union type are those signatures that are present and identical in each of the
// constituent types, except that non-generic signatures may differ in return types. When signatures
// differ in return types, the resulting return type is the union of the constituent return types.
// The signatures of a union type are those signatures that are present in each of the constituent types.
// Generic signatures must match exactly, but non-generic signatures are allowed to have extra optional
// parameters and may differ in return types. When signatures differ in return types, the resulting return
// type is the union of the constituent return types.
function getUnionSignatures(types: Type[], kind: SignatureKind): Signature[] {
let signatureLists = map(types, t => getSignaturesOfType(t, kind));
let result: Signature[] = undefined;
for (let source of signatureLists[0]) {
let unionSignatures = findMatchingSignatures(source, signatureLists);
if (unionSignatures) {
let signature: Signature = undefined;
if (unionSignatures.length === 1 || source.typeParameters) {
signature = source;
for (let i = 0; i < signatureLists.length; i++) {
for (let signature of signatureLists[i]) {
// Only process signatures with parameter lists that aren't already in the result list
if (!result || !findMatchingSignature(result, signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ true)) {
let unionSignatures = findMatchingSignatures(signatureLists, signature, i);
if (unionSignatures) {
let s = signature;
// Union the result types when more than one signature matches
if (unionSignatures.length > 1) {
s = cloneSignature(signature);
// Clear resolved return type we possibly got from cloneSignature
s.resolvedReturnType = undefined;
s.unionSignatures = unionSignatures;
}
(result || (result = [])).push(s);
}
}
else {
signature = cloneSignature(source);
// Clear resolved return type we possibly got from cloneSignature
signature.resolvedReturnType = undefined;
signature.unionSignatures = unionSignatures;
}
(result || (result = [])).push(signature);
}
}
return result || emptyArray;
@@ -5272,7 +5286,7 @@ namespace ts {
}
let result = Ternary.True;
for (let i = 0, len = sourceSignatures.length; i < len; ++i) {
let related = compareSignatures(sourceSignatures[i], targetSignatures[i], /*compareReturnTypes*/ true, isRelatedTo);
let related = compareSignatures(sourceSignatures[i], targetSignatures[i], /*partialMatch*/ false, /*ignoreReturnTypes*/ false, isRelatedTo);
if (!related) {
return Ternary.False;
}
@@ -5402,14 +5416,18 @@ namespace ts {
return compareTypes(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp));
}
function compareSignatures(source: Signature, target: Signature, compareReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary {
function compareSignatures(source: Signature, target: Signature, partialMatch: boolean, ignoreReturnTypes: boolean, compareTypes: (s: Type, t: Type) => Ternary): Ternary {
if (source === target) {
return Ternary.True;
}
if (source.parameters.length !== target.parameters.length ||
source.minArgumentCount !== target.minArgumentCount ||
source.hasRestParameter !== target.hasRestParameter) {
return Ternary.False;
if (!partialMatch ||
source.parameters.length < target.parameters.length && !source.hasRestParameter ||
source.minArgumentCount > target.minArgumentCount) {
return Ternary.False;
}
}
let result = Ternary.True;
if (source.typeParameters && target.typeParameters) {
@@ -5431,16 +5449,18 @@ namespace ts {
// M and N (the signatures) are instantiated using type Any as the type argument for all type parameters declared by M and N
source = getErasedSignature(source);
target = getErasedSignature(target);
for (let i = 0, len = source.parameters.length; i < len; i++) {
let s = source.hasRestParameter && i === len - 1 ? getRestTypeOfSignature(source) : getTypeOfSymbol(source.parameters[i]);
let t = target.hasRestParameter && i === len - 1 ? getRestTypeOfSignature(target) : getTypeOfSymbol(target.parameters[i]);
let sourceLen = source.parameters.length;
let targetLen = target.parameters.length;
for (let i = 0; i < targetLen; i++) {
let s = source.hasRestParameter && i === sourceLen - 1 ? getRestTypeOfSignature(source) : getTypeOfSymbol(source.parameters[i]);
let t = target.hasRestParameter && i === targetLen - 1 ? getRestTypeOfSignature(target) : getTypeOfSymbol(target.parameters[i]);
let related = compareTypes(s, t);
if (!related) {
return Ternary.False;
}
result &= related;
}
if (compareReturnTypes) {
if (!ignoreReturnTypes) {
result &= compareTypes(getReturnTypeOfSignature(source), getReturnTypeOfSignature(target));
}
return result;
@@ -6954,20 +6974,13 @@ namespace ts {
let signatureList: Signature[];
let types = (<UnionType>type).types;
for (let current of types) {
// The signature set of all constituent type with call signatures should match
// So number of signatures allowed is either 0 or 1
if (signatureList &&
getSignaturesOfStructuredType(current, SignatureKind.Call).length > 1) {
return undefined;
}
let signature = getNonGenericSignature(current);
if (signature) {
if (!signatureList) {
// This signature will contribute to contextual union signature
signatureList = [signature];
}
else if (!compareSignatures(signatureList[0], signature, /*compareReturnTypes*/ false, compareTypes)) {
else if (!compareSignatures(signatureList[0], signature, /*partialMatch*/ false, /*ignoreReturnTypes*/ true, compareTypes)) {
// Signatures aren't identical, do not use
return undefined;
}
@@ -82,5 +82,7 @@ var x4: IWithCallSignatures | IWithCallSignatures4 = a => /*here a should be any
>IWithCallSignatures : Symbol(IWithCallSignatures, Decl(contextualTypeWithUnionTypeCallSignatures.ts, 9, 1))
>IWithCallSignatures4 : Symbol(IWithCallSignatures4, Decl(contextualTypeWithUnionTypeCallSignatures.ts, 18, 1))
>a : Symbol(a, Decl(contextualTypeWithUnionTypeCallSignatures.ts, 35, 52))
>a.toString : Symbol(Number.toString, Decl(lib.d.ts, 458, 18))
>a : Symbol(a, Decl(contextualTypeWithUnionTypeCallSignatures.ts, 35, 52))
>toString : Symbol(Number.toString, Decl(lib.d.ts, 458, 18))
@@ -90,10 +90,10 @@ var x4: IWithCallSignatures | IWithCallSignatures4 = a => /*here a should be any
>x4 : IWithCallSignatures | IWithCallSignatures4
>IWithCallSignatures : IWithCallSignatures
>IWithCallSignatures4 : IWithCallSignatures4
>a => /*here a should be any*/ a.toString() : (a: any) => any
>a : any
>a.toString() : any
>a.toString : any
>a : any
>toString : any
>a => /*here a should be any*/ a.toString() : (a: number) => string
>a : number
>a.toString() : string
>a.toString : (radix?: number) => string
>a : number
>toString : (radix?: number) => string
@@ -1,11 +1,10 @@
tests/cases/compiler/mismatchedExplicitTypeParameterAndArgumentType.ts(7,30): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/compiler/mismatchedExplicitTypeParameterAndArgumentType.ts(10,30): error TS2345: Argument of type '(number | string)[]' is not assignable to parameter of type 'number[]'.
Type 'number | string' is not assignable to type 'number'.
Type 'string' is not assignable to type 'number'.
tests/cases/compiler/mismatchedExplicitTypeParameterAndArgumentType.ts(11,11): error TS2346: Supplied parameters do not match any signature of call target.
==== tests/cases/compiler/mismatchedExplicitTypeParameterAndArgumentType.ts (3 errors) ====
==== tests/cases/compiler/mismatchedExplicitTypeParameterAndArgumentType.ts (2 errors) ====
function map<T, U>(xs: T[], f: (x: T) => U) {
var ys: U[] = [];
xs.forEach(x => ys.push(f(x)));
@@ -13,8 +12,6 @@ tests/cases/compiler/mismatchedExplicitTypeParameterAndArgumentType.ts(11,11): e
}
var r0 = map([1, ""], (x) => x.toString());
~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
var r5 = map<any, any>([1, ""], (x) => x.toString());
var r6 = map<Object, Object>([1, ""], (x) => x.toString());
var r7 = map<number, string>([1, ""], (x) => x.toString()); // error
@@ -1,103 +0,0 @@
tests/cases/conformance/expressions/typeGuards/typeGuardsInConditionalExpression.ts(93,22): error TS2349: Cannot invoke an expression whose type lacks a call signature.
==== tests/cases/conformance/expressions/typeGuards/typeGuardsInConditionalExpression.ts (1 errors) ====
// In the true expression of a conditional expression,
// the type of a variable or parameter is narrowed by any type guard in the condition when true,
// provided the true expression contains no assignments to the variable or parameter.
// In the false expression of a conditional expression,
// the type of a variable or parameter is narrowed by any type guard in the condition when false,
// provided the false expression contains no assignments to the variable or parameter.
function foo(x: number | string) {
return typeof x === "string"
? x.length // string
: x++; // number
}
function foo2(x: number | string) {
// x is assigned in the if true branch, the type is not narrowed
return typeof x === "string"
? (x = 10 && x)// string | number
: x; // string | number
}
function foo3(x: number | string) {
// x is assigned in the if false branch, the type is not narrowed
// even though assigned using same type as narrowed expression
return typeof x === "string"
? (x = "Hello" && x) // string | number
: x; // string | number
}
function foo4(x: number | string) {
// false branch updates the variable - so here it is not number
// even though assigned using same type as narrowed expression
return typeof x === "string"
? x // string | number
: (x = 10 && x); // string | number
}
function foo5(x: number | string) {
// false branch updates the variable - so here it is not number
return typeof x === "string"
? x // string | number
: (x = "hello" && x); // string | number
}
function foo6(x: number | string) {
// Modify in both branches
return typeof x === "string"
? (x = 10 && x) // string | number
: (x = "hello" && x); // string | number
}
function foo7(x: number | string | boolean) {
return typeof x === "string"
? x === "hello" // string
: typeof x === "boolean"
? x // boolean
: x == 10; // number
}
function foo8(x: number | string | boolean) {
var b: number | boolean;
return typeof x === "string"
? x === "hello"
: ((b = x) && // number | boolean
(typeof x === "boolean"
? x // boolean
: x == 10)); // number
}
function foo9(x: number | string) {
var y = 10;
// usage of x or assignment to separate variable shouldn't cause narrowing of type to stop
return typeof x === "string"
? ((y = x.length) && x === "hello") // string
: x === 10; // number
}
function foo10(x: number | string | boolean) {
// Mixing typeguards
var b: boolean | number;
return typeof x === "string"
? x // string
: ((b = x) // x is number | boolean
&& typeof x === "number"
&& x.toString()); // x is number
}
function foo11(x: number | string | boolean) {
// Mixing typeguards
// Assigning value to x deep inside another guard stops narrowing of type too
var b: number | boolean | string;
return typeof x === "string"
? x // number | boolean | string - changed in the false branch
: ((b = x) // x is number | boolean | string - because the assignment changed it
&& typeof x === "number"
&& (x = 10) // assignment to x
&& x); // x is number | boolean | string
}
function foo12(x: number | string | boolean) {
// Mixing typeguards
// Assigning value to x in outer guard shouldn't stop narrowing in the inner expression
var b: number | boolean | string;
return typeof x === "string"
? (x = 10 && x.toString().length) // number | boolean | string - changed here
~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
: ((b = x) // x is number | boolean | string - changed in true branch
&& typeof x === "number"
&& x); // x is number
}
@@ -0,0 +1,251 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardsInConditionalExpression.ts ===
// In the true expression of a conditional expression,
// the type of a variable or parameter is narrowed by any type guard in the condition when true,
// provided the true expression contains no assignments to the variable or parameter.
// In the false expression of a conditional expression,
// the type of a variable or parameter is narrowed by any type guard in the condition when false,
// provided the false expression contains no assignments to the variable or parameter.
function foo(x: number | string) {
>foo : Symbol(foo, Decl(typeGuardsInConditionalExpression.ts, 0, 0))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 7, 13))
return typeof x === "string"
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 7, 13))
? x.length // string
>x.length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 7, 13))
>length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
: x++; // number
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 7, 13))
}
function foo2(x: number | string) {
>foo2 : Symbol(foo2, Decl(typeGuardsInConditionalExpression.ts, 11, 1))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 12, 14))
// x is assigned in the if true branch, the type is not narrowed
return typeof x === "string"
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 12, 14))
? (x = 10 && x)// string | number
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 12, 14))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 12, 14))
: x; // string | number
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 12, 14))
}
function foo3(x: number | string) {
>foo3 : Symbol(foo3, Decl(typeGuardsInConditionalExpression.ts, 17, 1))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 18, 14))
// x is assigned in the if false branch, the type is not narrowed
// even though assigned using same type as narrowed expression
return typeof x === "string"
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 18, 14))
? (x = "Hello" && x) // string | number
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 18, 14))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 18, 14))
: x; // string | number
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 18, 14))
}
function foo4(x: number | string) {
>foo4 : Symbol(foo4, Decl(typeGuardsInConditionalExpression.ts, 24, 1))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 25, 14))
// false branch updates the variable - so here it is not number
// even though assigned using same type as narrowed expression
return typeof x === "string"
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 25, 14))
? x // string | number
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 25, 14))
: (x = 10 && x); // string | number
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 25, 14))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 25, 14))
}
function foo5(x: number | string) {
>foo5 : Symbol(foo5, Decl(typeGuardsInConditionalExpression.ts, 31, 1))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 32, 14))
// false branch updates the variable - so here it is not number
return typeof x === "string"
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 32, 14))
? x // string | number
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 32, 14))
: (x = "hello" && x); // string | number
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 32, 14))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 32, 14))
}
function foo6(x: number | string) {
>foo6 : Symbol(foo6, Decl(typeGuardsInConditionalExpression.ts, 37, 1))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 38, 14))
// Modify in both branches
return typeof x === "string"
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 38, 14))
? (x = 10 && x) // string | number
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 38, 14))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 38, 14))
: (x = "hello" && x); // string | number
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 38, 14))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 38, 14))
}
function foo7(x: number | string | boolean) {
>foo7 : Symbol(foo7, Decl(typeGuardsInConditionalExpression.ts, 43, 1))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 44, 14))
return typeof x === "string"
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 44, 14))
? x === "hello" // string
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 44, 14))
: typeof x === "boolean"
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 44, 14))
? x // boolean
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 44, 14))
: x == 10; // number
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 44, 14))
}
function foo8(x: number | string | boolean) {
>foo8 : Symbol(foo8, Decl(typeGuardsInConditionalExpression.ts, 50, 1))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 51, 14))
var b: number | boolean;
>b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 52, 7))
return typeof x === "string"
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 51, 14))
? x === "hello"
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 51, 14))
: ((b = x) && // number | boolean
>b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 52, 7))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 51, 14))
(typeof x === "boolean"
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 51, 14))
? x // boolean
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 51, 14))
: x == 10)); // number
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 51, 14))
}
function foo9(x: number | string) {
>foo9 : Symbol(foo9, Decl(typeGuardsInConditionalExpression.ts, 59, 1))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 60, 14))
var y = 10;
>y : Symbol(y, Decl(typeGuardsInConditionalExpression.ts, 61, 7))
// usage of x or assignment to separate variable shouldn't cause narrowing of type to stop
return typeof x === "string"
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 60, 14))
? ((y = x.length) && x === "hello") // string
>y : Symbol(y, Decl(typeGuardsInConditionalExpression.ts, 61, 7))
>x.length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 60, 14))
>length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 60, 14))
: x === 10; // number
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 60, 14))
}
function foo10(x: number | string | boolean) {
>foo10 : Symbol(foo10, Decl(typeGuardsInConditionalExpression.ts, 66, 1))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 67, 15))
// Mixing typeguards
var b: boolean | number;
>b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 69, 7))
return typeof x === "string"
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 67, 15))
? x // string
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 67, 15))
: ((b = x) // x is number | boolean
>b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 69, 7))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 67, 15))
&& typeof x === "number"
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 67, 15))
&& x.toString()); // x is number
>x.toString : Symbol(Number.toString, Decl(lib.d.ts, 458, 18))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 67, 15))
>toString : Symbol(Number.toString, Decl(lib.d.ts, 458, 18))
}
function foo11(x: number | string | boolean) {
>foo11 : Symbol(foo11, Decl(typeGuardsInConditionalExpression.ts, 75, 1))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 76, 15))
// Mixing typeguards
// Assigning value to x deep inside another guard stops narrowing of type too
var b: number | boolean | string;
>b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 79, 7))
return typeof x === "string"
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 76, 15))
? x // number | boolean | string - changed in the false branch
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 76, 15))
: ((b = x) // x is number | boolean | string - because the assignment changed it
>b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 79, 7))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 76, 15))
&& typeof x === "number"
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 76, 15))
&& (x = 10) // assignment to x
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 76, 15))
&& x); // x is number | boolean | string
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 76, 15))
}
function foo12(x: number | string | boolean) {
>foo12 : Symbol(foo12, Decl(typeGuardsInConditionalExpression.ts, 86, 1))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 87, 15))
// Mixing typeguards
// Assigning value to x in outer guard shouldn't stop narrowing in the inner expression
var b: number | boolean | string;
>b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 90, 7))
return typeof x === "string"
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 87, 15))
? (x = 10 && x.toString().length) // number | boolean | string - changed here
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 87, 15))
>x.toString().length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
>x.toString : Symbol(toString, Decl(lib.d.ts, 458, 18), Decl(lib.d.ts, 277, 18), Decl(lib.d.ts, 96, 26))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 87, 15))
>toString : Symbol(toString, Decl(lib.d.ts, 458, 18), Decl(lib.d.ts, 277, 18), Decl(lib.d.ts, 96, 26))
>length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
: ((b = x) // x is number | boolean | string - changed in true branch
>b : Symbol(b, Decl(typeGuardsInConditionalExpression.ts, 90, 7))
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 87, 15))
&& typeof x === "number"
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 87, 15))
&& x); // x is number
>x : Symbol(x, Decl(typeGuardsInConditionalExpression.ts, 87, 15))
}
@@ -0,0 +1,388 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardsInConditionalExpression.ts ===
// In the true expression of a conditional expression,
// the type of a variable or parameter is narrowed by any type guard in the condition when true,
// provided the true expression contains no assignments to the variable or parameter.
// In the false expression of a conditional expression,
// the type of a variable or parameter is narrowed by any type guard in the condition when false,
// provided the false expression contains no assignments to the variable or parameter.
function foo(x: number | string) {
>foo : (x: number | string) => number
>x : number | string
return typeof x === "string"
>typeof x === "string" ? x.length // string : x++ : number
>typeof x === "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
? x.length // string
>x.length : number
>x : string
>length : number
: x++; // number
>x++ : number
>x : number
}
function foo2(x: number | string) {
>foo2 : (x: number | string) => number | string
>x : number | string
// x is assigned in the if true branch, the type is not narrowed
return typeof x === "string"
>typeof x === "string" ? (x = 10 && x)// string | number : x : number | string
>typeof x === "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
? (x = 10 && x)// string | number
>(x = 10 && x) : number | string
>x = 10 && x : number | string
>x : number | string
>10 && x : number | string
>10 : number
>x : number | string
: x; // string | number
>x : number | string
}
function foo3(x: number | string) {
>foo3 : (x: number | string) => number | string
>x : number | string
// x is assigned in the if false branch, the type is not narrowed
// even though assigned using same type as narrowed expression
return typeof x === "string"
>typeof x === "string" ? (x = "Hello" && x) // string | number : x : number | string
>typeof x === "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
? (x = "Hello" && x) // string | number
>(x = "Hello" && x) : number | string
>x = "Hello" && x : number | string
>x : number | string
>"Hello" && x : number | string
>"Hello" : string
>x : number | string
: x; // string | number
>x : number | string
}
function foo4(x: number | string) {
>foo4 : (x: number | string) => number | string
>x : number | string
// false branch updates the variable - so here it is not number
// even though assigned using same type as narrowed expression
return typeof x === "string"
>typeof x === "string" ? x // string | number : (x = 10 && x) : number | string
>typeof x === "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
? x // string | number
>x : number | string
: (x = 10 && x); // string | number
>(x = 10 && x) : number | string
>x = 10 && x : number | string
>x : number | string
>10 && x : number | string
>10 : number
>x : number | string
}
function foo5(x: number | string) {
>foo5 : (x: number | string) => number | string
>x : number | string
// false branch updates the variable - so here it is not number
return typeof x === "string"
>typeof x === "string" ? x // string | number : (x = "hello" && x) : number | string
>typeof x === "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
? x // string | number
>x : number | string
: (x = "hello" && x); // string | number
>(x = "hello" && x) : number | string
>x = "hello" && x : number | string
>x : number | string
>"hello" && x : number | string
>"hello" : string
>x : number | string
}
function foo6(x: number | string) {
>foo6 : (x: number | string) => number | string
>x : number | string
// Modify in both branches
return typeof x === "string"
>typeof x === "string" ? (x = 10 && x) // string | number : (x = "hello" && x) : number | string
>typeof x === "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
? (x = 10 && x) // string | number
>(x = 10 && x) : number | string
>x = 10 && x : number | string
>x : number | string
>10 && x : number | string
>10 : number
>x : number | string
: (x = "hello" && x); // string | number
>(x = "hello" && x) : number | string
>x = "hello" && x : number | string
>x : number | string
>"hello" && x : number | string
>"hello" : string
>x : number | string
}
function foo7(x: number | string | boolean) {
>foo7 : (x: number | string | boolean) => boolean
>x : number | string | boolean
return typeof x === "string"
>typeof x === "string" ? x === "hello" // string : typeof x === "boolean" ? x // boolean : x == 10 : boolean
>typeof x === "string" : boolean
>typeof x : string
>x : number | string | boolean
>"string" : string
? x === "hello" // string
>x === "hello" : boolean
>x : string
>"hello" : string
: typeof x === "boolean"
>typeof x === "boolean" ? x // boolean : x == 10 : boolean
>typeof x === "boolean" : boolean
>typeof x : string
>x : number | boolean
>"boolean" : string
? x // boolean
>x : boolean
: x == 10; // number
>x == 10 : boolean
>x : number
>10 : number
}
function foo8(x: number | string | boolean) {
>foo8 : (x: number | string | boolean) => boolean
>x : number | string | boolean
var b: number | boolean;
>b : number | boolean
return typeof x === "string"
>typeof x === "string" ? x === "hello" : ((b = x) && // number | boolean (typeof x === "boolean" ? x // boolean : x == 10)) : boolean
>typeof x === "string" : boolean
>typeof x : string
>x : number | string | boolean
>"string" : string
? x === "hello"
>x === "hello" : boolean
>x : string
>"hello" : string
: ((b = x) && // number | boolean
>((b = x) && // number | boolean (typeof x === "boolean" ? x // boolean : x == 10)) : boolean
>(b = x) && // number | boolean (typeof x === "boolean" ? x // boolean : x == 10) : boolean
>(b = x) : number | boolean
>b = x : number | boolean
>b : number | boolean
>x : number | boolean
(typeof x === "boolean"
>(typeof x === "boolean" ? x // boolean : x == 10) : boolean
>typeof x === "boolean" ? x // boolean : x == 10 : boolean
>typeof x === "boolean" : boolean
>typeof x : string
>x : number | boolean
>"boolean" : string
? x // boolean
>x : boolean
: x == 10)); // number
>x == 10 : boolean
>x : number
>10 : number
}
function foo9(x: number | string) {
>foo9 : (x: number | string) => boolean
>x : number | string
var y = 10;
>y : number
>10 : number
// usage of x or assignment to separate variable shouldn't cause narrowing of type to stop
return typeof x === "string"
>typeof x === "string" ? ((y = x.length) && x === "hello") // string : x === 10 : boolean
>typeof x === "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
? ((y = x.length) && x === "hello") // string
>((y = x.length) && x === "hello") : boolean
>(y = x.length) && x === "hello" : boolean
>(y = x.length) : number
>y = x.length : number
>y : number
>x.length : number
>x : string
>length : number
>x === "hello" : boolean
>x : string
>"hello" : string
: x === 10; // number
>x === 10 : boolean
>x : number
>10 : number
}
function foo10(x: number | string | boolean) {
>foo10 : (x: number | string | boolean) => string
>x : number | string | boolean
// Mixing typeguards
var b: boolean | number;
>b : boolean | number
return typeof x === "string"
>typeof x === "string" ? x // string : ((b = x) // x is number | boolean && typeof x === "number" && x.toString()) : string
>typeof x === "string" : boolean
>typeof x : string
>x : number | string | boolean
>"string" : string
? x // string
>x : string
: ((b = x) // x is number | boolean
>((b = x) // x is number | boolean && typeof x === "number" && x.toString()) : string
>(b = x) // x is number | boolean && typeof x === "number" && x.toString() : string
>(b = x) // x is number | boolean && typeof x === "number" : boolean
>(b = x) : number | boolean
>b = x : number | boolean
>b : boolean | number
>x : number | boolean
&& typeof x === "number"
>typeof x === "number" : boolean
>typeof x : string
>x : number | boolean
>"number" : string
&& x.toString()); // x is number
>x.toString() : string
>x.toString : (radix?: number) => string
>x : number
>toString : (radix?: number) => string
}
function foo11(x: number | string | boolean) {
>foo11 : (x: number | string | boolean) => number | string | boolean
>x : number | string | boolean
// Mixing typeguards
// Assigning value to x deep inside another guard stops narrowing of type too
var b: number | boolean | string;
>b : number | boolean | string
return typeof x === "string"
>typeof x === "string" ? x // number | boolean | string - changed in the false branch : ((b = x) // x is number | boolean | string - because the assignment changed it && typeof x === "number" && (x = 10) // assignment to x && x) : number | string | boolean
>typeof x === "string" : boolean
>typeof x : string
>x : number | string | boolean
>"string" : string
? x // number | boolean | string - changed in the false branch
>x : number | string | boolean
: ((b = x) // x is number | boolean | string - because the assignment changed it
>((b = x) // x is number | boolean | string - because the assignment changed it && typeof x === "number" && (x = 10) // assignment to x && x) : number | string | boolean
>(b = x) // x is number | boolean | string - because the assignment changed it && typeof x === "number" && (x = 10) // assignment to x && x : number | string | boolean
>(b = x) // x is number | boolean | string - because the assignment changed it && typeof x === "number" && (x = 10) : number
>(b = x) // x is number | boolean | string - because the assignment changed it && typeof x === "number" : boolean
>(b = x) : number | string | boolean
>b = x : number | string | boolean
>b : number | boolean | string
>x : number | string | boolean
&& typeof x === "number"
>typeof x === "number" : boolean
>typeof x : string
>x : number | string | boolean
>"number" : string
&& (x = 10) // assignment to x
>(x = 10) : number
>x = 10 : number
>x : number | string | boolean
>10 : number
&& x); // x is number | boolean | string
>x : number | string | boolean
}
function foo12(x: number | string | boolean) {
>foo12 : (x: number | string | boolean) => number
>x : number | string | boolean
// Mixing typeguards
// Assigning value to x in outer guard shouldn't stop narrowing in the inner expression
var b: number | boolean | string;
>b : number | boolean | string
return typeof x === "string"
>typeof x === "string" ? (x = 10 && x.toString().length) // number | boolean | string - changed here : ((b = x) // x is number | boolean | string - changed in true branch && typeof x === "number" && x) : number
>typeof x === "string" : boolean
>typeof x : string
>x : number | string | boolean
>"string" : string
? (x = 10 && x.toString().length) // number | boolean | string - changed here
>(x = 10 && x.toString().length) : number
>x = 10 && x.toString().length : number
>x : number | string | boolean
>10 && x.toString().length : number
>10 : number
>x.toString().length : number
>x.toString() : string
>x.toString : ((radix?: number) => string) | (() => string)
>x : number | string | boolean
>toString : ((radix?: number) => string) | (() => string)
>length : number
: ((b = x) // x is number | boolean | string - changed in true branch
>((b = x) // x is number | boolean | string - changed in true branch && typeof x === "number" && x) : number
>(b = x) // x is number | boolean | string - changed in true branch && typeof x === "number" && x : number
>(b = x) // x is number | boolean | string - changed in true branch && typeof x === "number" : boolean
>(b = x) : number | string | boolean
>b = x : number | string | boolean
>b : number | boolean | string
>x : number | string | boolean
&& typeof x === "number"
>typeof x === "number" : boolean
>typeof x : string
>x : number | string | boolean
>"number" : string
&& x); // x is number
>x : number
}
@@ -1,160 +0,0 @@
tests/cases/conformance/expressions/typeGuards/typeGuardsInIfStatement.ts(127,23): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/expressions/typeGuards/typeGuardsInIfStatement.ts(131,22): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/expressions/typeGuards/typeGuardsInIfStatement.ts(139,16): error TS2349: Cannot invoke an expression whose type lacks a call signature.
==== tests/cases/conformance/expressions/typeGuards/typeGuardsInIfStatement.ts (3 errors) ====
// In the true branch statement of an �if� statement,
// the type of a variable or parameter is narrowed by any type guard in the �if� condition when true,
// provided the true branch statement contains no assignments to the variable or parameter.
// In the false branch statement of an �if� statement,
// the type of a variable or parameter is narrowed by any type guard in the �if� condition when false,
// provided the false branch statement contains no assignments to the variable or parameter
function foo(x: number | string) {
if (typeof x === "string") {
return x.length; // string
}
else {
return x++; // number
}
}
function foo2(x: number | string) {
// x is assigned in the if true branch, the type is not narrowed
if (typeof x === "string") {
x = 10;
return x; // string | number
}
else {
return x; // string | number
}
}
function foo3(x: number | string) {
// x is assigned in the if true branch, the type is not narrowed
if (typeof x === "string") {
x = "Hello"; // even though assigned using same type as narrowed expression
return x; // string | number
}
else {
return x; // string | number
}
}
function foo4(x: number | string) {
// false branch updates the variable - so here it is not number
if (typeof x === "string") {
return x; // string | number
}
else {
x = 10; // even though assigned number - this should result in x to be string | number
return x; // string | number
}
}
function foo5(x: number | string) {
// false branch updates the variable - so here it is not number
if (typeof x === "string") {
return x; // string | number
}
else {
x = "hello";
return x; // string | number
}
}
function foo6(x: number | string) {
// Modify in both branches
if (typeof x === "string") {
x = 10;
return x; // string | number
}
else {
x = "hello";
return x; // string | number
}
}
function foo7(x: number | string | boolean) {
if (typeof x === "string") {
return x === "hello"; // string
}
else if (typeof x === "boolean") {
return x; // boolean
}
else {
return x == 10; // number
}
}
function foo8(x: number | string | boolean) {
if (typeof x === "string") {
return x === "hello"; // string
}
else {
var b: number | boolean = x; // number | boolean
if (typeof x === "boolean") {
return x; // boolean
}
else {
return x == 10; // number
}
}
}
function foo9(x: number | string) {
var y = 10;
if (typeof x === "string") {
// usage of x or assignment to separate variable shouldn't cause narrowing of type to stop
y = x.length;
return x === "hello"; // string
}
else {
return x == 10; // number
}
}
function foo10(x: number | string | boolean) {
// Mixing typeguard narrowing in if statement with conditional expression typeguard
if (typeof x === "string") {
return x === "hello"; // string
}
else {
var y: boolean | string;
var b = x; // number | boolean
return typeof x === "number"
? x === 10 // number
: x; // x should be boolean
}
}
function foo11(x: number | string | boolean) {
// Mixing typeguard narrowing in if statement with conditional expression typeguard
// Assigning value to x deep inside another guard stops narrowing of type too
if (typeof x === "string") {
return x; // string | number | boolean - x changed in else branch
}
else {
var y: number| boolean | string;
var b = x; // number | boolean | string - because below we are changing value of x in if statement
return typeof x === "number"
? (
// change value of x
x = 10 && x.toString() // number | boolean | string
~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
)
: (
// do not change value
y = x && x.toString() // number | boolean | string
~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
);
}
}
function foo12(x: number | string | boolean) {
// Mixing typeguard narrowing in if statement with conditional expression typeguard
// Assigning value to x in outer guard shouldn't stop narrowing in the inner expression
if (typeof x === "string") {
return x.toString(); // string | number | boolean - x changed in else branch
~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
}
else {
x = 10;
var b = x; // number | boolean | string
return typeof x === "number"
? x.toString() // number
: x.toString(); // boolean | string
}
}
@@ -0,0 +1,304 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardsInIfStatement.ts ===
// In the true branch statement of an �if� statement,
// the type of a variable or parameter is narrowed by any type guard in the �if� condition when true,
// provided the true branch statement contains no assignments to the variable or parameter.
// In the false branch statement of an �if� statement,
// the type of a variable or parameter is narrowed by any type guard in the �if� condition when false,
// provided the false branch statement contains no assignments to the variable or parameter
function foo(x: number | string) {
>foo : Symbol(foo, Decl(typeGuardsInIfStatement.ts, 0, 0))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 6, 13))
if (typeof x === "string") {
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 6, 13))
return x.length; // string
>x.length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 6, 13))
>length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
}
else {
return x++; // number
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 6, 13))
}
}
function foo2(x: number | string) {
>foo2 : Symbol(foo2, Decl(typeGuardsInIfStatement.ts, 13, 1))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 14, 14))
// x is assigned in the if true branch, the type is not narrowed
if (typeof x === "string") {
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 14, 14))
x = 10;
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 14, 14))
return x; // string | number
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 14, 14))
}
else {
return x; // string | number
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 14, 14))
}
}
function foo3(x: number | string) {
>foo3 : Symbol(foo3, Decl(typeGuardsInIfStatement.ts, 23, 1))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 24, 14))
// x is assigned in the if true branch, the type is not narrowed
if (typeof x === "string") {
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 24, 14))
x = "Hello"; // even though assigned using same type as narrowed expression
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 24, 14))
return x; // string | number
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 24, 14))
}
else {
return x; // string | number
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 24, 14))
}
}
function foo4(x: number | string) {
>foo4 : Symbol(foo4, Decl(typeGuardsInIfStatement.ts, 33, 1))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 34, 14))
// false branch updates the variable - so here it is not number
if (typeof x === "string") {
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 34, 14))
return x; // string | number
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 34, 14))
}
else {
x = 10; // even though assigned number - this should result in x to be string | number
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 34, 14))
return x; // string | number
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 34, 14))
}
}
function foo5(x: number | string) {
>foo5 : Symbol(foo5, Decl(typeGuardsInIfStatement.ts, 43, 1))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 44, 14))
// false branch updates the variable - so here it is not number
if (typeof x === "string") {
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 44, 14))
return x; // string | number
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 44, 14))
}
else {
x = "hello";
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 44, 14))
return x; // string | number
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 44, 14))
}
}
function foo6(x: number | string) {
>foo6 : Symbol(foo6, Decl(typeGuardsInIfStatement.ts, 53, 1))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 54, 14))
// Modify in both branches
if (typeof x === "string") {
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 54, 14))
x = 10;
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 54, 14))
return x; // string | number
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 54, 14))
}
else {
x = "hello";
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 54, 14))
return x; // string | number
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 54, 14))
}
}
function foo7(x: number | string | boolean) {
>foo7 : Symbol(foo7, Decl(typeGuardsInIfStatement.ts, 64, 1))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 65, 14))
if (typeof x === "string") {
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 65, 14))
return x === "hello"; // string
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 65, 14))
}
else if (typeof x === "boolean") {
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 65, 14))
return x; // boolean
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 65, 14))
}
else {
return x == 10; // number
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 65, 14))
}
}
function foo8(x: number | string | boolean) {
>foo8 : Symbol(foo8, Decl(typeGuardsInIfStatement.ts, 75, 1))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 76, 14))
if (typeof x === "string") {
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 76, 14))
return x === "hello"; // string
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 76, 14))
}
else {
var b: number | boolean = x; // number | boolean
>b : Symbol(b, Decl(typeGuardsInIfStatement.ts, 81, 11))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 76, 14))
if (typeof x === "boolean") {
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 76, 14))
return x; // boolean
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 76, 14))
}
else {
return x == 10; // number
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 76, 14))
}
}
}
function foo9(x: number | string) {
>foo9 : Symbol(foo9, Decl(typeGuardsInIfStatement.ts, 89, 1))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 90, 14))
var y = 10;
>y : Symbol(y, Decl(typeGuardsInIfStatement.ts, 91, 7))
if (typeof x === "string") {
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 90, 14))
// usage of x or assignment to separate variable shouldn't cause narrowing of type to stop
y = x.length;
>y : Symbol(y, Decl(typeGuardsInIfStatement.ts, 91, 7))
>x.length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 90, 14))
>length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
return x === "hello"; // string
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 90, 14))
}
else {
return x == 10; // number
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 90, 14))
}
}
function foo10(x: number | string | boolean) {
>foo10 : Symbol(foo10, Decl(typeGuardsInIfStatement.ts, 100, 1))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 101, 15))
// Mixing typeguard narrowing in if statement with conditional expression typeguard
if (typeof x === "string") {
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 101, 15))
return x === "hello"; // string
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 101, 15))
}
else {
var y: boolean | string;
>y : Symbol(y, Decl(typeGuardsInIfStatement.ts, 107, 11))
var b = x; // number | boolean
>b : Symbol(b, Decl(typeGuardsInIfStatement.ts, 108, 11))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 101, 15))
return typeof x === "number"
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 101, 15))
? x === 10 // number
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 101, 15))
: x; // x should be boolean
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 101, 15))
}
}
function foo11(x: number | string | boolean) {
>foo11 : Symbol(foo11, Decl(typeGuardsInIfStatement.ts, 113, 1))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 114, 15))
// Mixing typeguard narrowing in if statement with conditional expression typeguard
// Assigning value to x deep inside another guard stops narrowing of type too
if (typeof x === "string") {
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 114, 15))
return x; // string | number | boolean - x changed in else branch
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 114, 15))
}
else {
var y: number| boolean | string;
>y : Symbol(y, Decl(typeGuardsInIfStatement.ts, 121, 11))
var b = x; // number | boolean | string - because below we are changing value of x in if statement
>b : Symbol(b, Decl(typeGuardsInIfStatement.ts, 122, 11))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 114, 15))
return typeof x === "number"
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 114, 15))
? (
// change value of x
x = 10 && x.toString() // number | boolean | string
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 114, 15))
>x.toString : Symbol(toString, Decl(lib.d.ts, 458, 18), Decl(lib.d.ts, 277, 18), Decl(lib.d.ts, 96, 26))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 114, 15))
>toString : Symbol(toString, Decl(lib.d.ts, 458, 18), Decl(lib.d.ts, 277, 18), Decl(lib.d.ts, 96, 26))
)
: (
// do not change value
y = x && x.toString() // number | boolean | string
>y : Symbol(y, Decl(typeGuardsInIfStatement.ts, 121, 11))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 114, 15))
>x.toString : Symbol(toString, Decl(lib.d.ts, 458, 18), Decl(lib.d.ts, 277, 18), Decl(lib.d.ts, 96, 26))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 114, 15))
>toString : Symbol(toString, Decl(lib.d.ts, 458, 18), Decl(lib.d.ts, 277, 18), Decl(lib.d.ts, 96, 26))
);
}
}
function foo12(x: number | string | boolean) {
>foo12 : Symbol(foo12, Decl(typeGuardsInIfStatement.ts, 133, 1))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 134, 15))
// Mixing typeguard narrowing in if statement with conditional expression typeguard
// Assigning value to x in outer guard shouldn't stop narrowing in the inner expression
if (typeof x === "string") {
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 134, 15))
return x.toString(); // string | number | boolean - x changed in else branch
>x.toString : Symbol(toString, Decl(lib.d.ts, 458, 18), Decl(lib.d.ts, 277, 18), Decl(lib.d.ts, 96, 26))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 134, 15))
>toString : Symbol(toString, Decl(lib.d.ts, 458, 18), Decl(lib.d.ts, 277, 18), Decl(lib.d.ts, 96, 26))
}
else {
x = 10;
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 134, 15))
var b = x; // number | boolean | string
>b : Symbol(b, Decl(typeGuardsInIfStatement.ts, 142, 11))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 134, 15))
return typeof x === "number"
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 134, 15))
? x.toString() // number
>x.toString : Symbol(Number.toString, Decl(lib.d.ts, 458, 18))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 134, 15))
>toString : Symbol(Number.toString, Decl(lib.d.ts, 458, 18))
: x.toString(); // boolean | string
>x.toString : Symbol(toString, Decl(lib.d.ts, 277, 18), Decl(lib.d.ts, 96, 26))
>x : Symbol(x, Decl(typeGuardsInIfStatement.ts, 134, 15))
>toString : Symbol(toString, Decl(lib.d.ts, 277, 18), Decl(lib.d.ts, 96, 26))
}
}
@@ -0,0 +1,405 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardsInIfStatement.ts ===
// In the true branch statement of an �if� statement,
// the type of a variable or parameter is narrowed by any type guard in the �if� condition when true,
// provided the true branch statement contains no assignments to the variable or parameter.
// In the false branch statement of an �if� statement,
// the type of a variable or parameter is narrowed by any type guard in the �if� condition when false,
// provided the false branch statement contains no assignments to the variable or parameter
function foo(x: number | string) {
>foo : (x: number | string) => number
>x : number | string
if (typeof x === "string") {
>typeof x === "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
return x.length; // string
>x.length : number
>x : string
>length : number
}
else {
return x++; // number
>x++ : number
>x : number
}
}
function foo2(x: number | string) {
>foo2 : (x: number | string) => number | string
>x : number | string
// x is assigned in the if true branch, the type is not narrowed
if (typeof x === "string") {
>typeof x === "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
x = 10;
>x = 10 : number
>x : number | string
>10 : number
return x; // string | number
>x : number | string
}
else {
return x; // string | number
>x : number | string
}
}
function foo3(x: number | string) {
>foo3 : (x: number | string) => number | string
>x : number | string
// x is assigned in the if true branch, the type is not narrowed
if (typeof x === "string") {
>typeof x === "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
x = "Hello"; // even though assigned using same type as narrowed expression
>x = "Hello" : string
>x : number | string
>"Hello" : string
return x; // string | number
>x : number | string
}
else {
return x; // string | number
>x : number | string
}
}
function foo4(x: number | string) {
>foo4 : (x: number | string) => number | string
>x : number | string
// false branch updates the variable - so here it is not number
if (typeof x === "string") {
>typeof x === "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
return x; // string | number
>x : number | string
}
else {
x = 10; // even though assigned number - this should result in x to be string | number
>x = 10 : number
>x : number | string
>10 : number
return x; // string | number
>x : number | string
}
}
function foo5(x: number | string) {
>foo5 : (x: number | string) => number | string
>x : number | string
// false branch updates the variable - so here it is not number
if (typeof x === "string") {
>typeof x === "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
return x; // string | number
>x : number | string
}
else {
x = "hello";
>x = "hello" : string
>x : number | string
>"hello" : string
return x; // string | number
>x : number | string
}
}
function foo6(x: number | string) {
>foo6 : (x: number | string) => number | string
>x : number | string
// Modify in both branches
if (typeof x === "string") {
>typeof x === "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
x = 10;
>x = 10 : number
>x : number | string
>10 : number
return x; // string | number
>x : number | string
}
else {
x = "hello";
>x = "hello" : string
>x : number | string
>"hello" : string
return x; // string | number
>x : number | string
}
}
function foo7(x: number | string | boolean) {
>foo7 : (x: number | string | boolean) => boolean
>x : number | string | boolean
if (typeof x === "string") {
>typeof x === "string" : boolean
>typeof x : string
>x : number | string | boolean
>"string" : string
return x === "hello"; // string
>x === "hello" : boolean
>x : string
>"hello" : string
}
else if (typeof x === "boolean") {
>typeof x === "boolean" : boolean
>typeof x : string
>x : number | boolean
>"boolean" : string
return x; // boolean
>x : boolean
}
else {
return x == 10; // number
>x == 10 : boolean
>x : number
>10 : number
}
}
function foo8(x: number | string | boolean) {
>foo8 : (x: number | string | boolean) => boolean
>x : number | string | boolean
if (typeof x === "string") {
>typeof x === "string" : boolean
>typeof x : string
>x : number | string | boolean
>"string" : string
return x === "hello"; // string
>x === "hello" : boolean
>x : string
>"hello" : string
}
else {
var b: number | boolean = x; // number | boolean
>b : number | boolean
>x : number | boolean
if (typeof x === "boolean") {
>typeof x === "boolean" : boolean
>typeof x : string
>x : number | boolean
>"boolean" : string
return x; // boolean
>x : boolean
}
else {
return x == 10; // number
>x == 10 : boolean
>x : number
>10 : number
}
}
}
function foo9(x: number | string) {
>foo9 : (x: number | string) => boolean
>x : number | string
var y = 10;
>y : number
>10 : number
if (typeof x === "string") {
>typeof x === "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
// usage of x or assignment to separate variable shouldn't cause narrowing of type to stop
y = x.length;
>y = x.length : number
>y : number
>x.length : number
>x : string
>length : number
return x === "hello"; // string
>x === "hello" : boolean
>x : string
>"hello" : string
}
else {
return x == 10; // number
>x == 10 : boolean
>x : number
>10 : number
}
}
function foo10(x: number | string | boolean) {
>foo10 : (x: number | string | boolean) => boolean
>x : number | string | boolean
// Mixing typeguard narrowing in if statement with conditional expression typeguard
if (typeof x === "string") {
>typeof x === "string" : boolean
>typeof x : string
>x : number | string | boolean
>"string" : string
return x === "hello"; // string
>x === "hello" : boolean
>x : string
>"hello" : string
}
else {
var y: boolean | string;
>y : boolean | string
var b = x; // number | boolean
>b : number | boolean
>x : number | boolean
return typeof x === "number"
>typeof x === "number" ? x === 10 // number : x : boolean
>typeof x === "number" : boolean
>typeof x : string
>x : number | boolean
>"number" : string
? x === 10 // number
>x === 10 : boolean
>x : number
>10 : number
: x; // x should be boolean
>x : boolean
}
}
function foo11(x: number | string | boolean) {
>foo11 : (x: number | string | boolean) => number | string | boolean
>x : number | string | boolean
// Mixing typeguard narrowing in if statement with conditional expression typeguard
// Assigning value to x deep inside another guard stops narrowing of type too
if (typeof x === "string") {
>typeof x === "string" : boolean
>typeof x : string
>x : number | string | boolean
>"string" : string
return x; // string | number | boolean - x changed in else branch
>x : number | string | boolean
}
else {
var y: number| boolean | string;
>y : number | boolean | string
var b = x; // number | boolean | string - because below we are changing value of x in if statement
>b : number | string | boolean
>x : number | string | boolean
return typeof x === "number"
>typeof x === "number" ? ( // change value of x x = 10 && x.toString() // number | boolean | string ) : ( // do not change value y = x && x.toString() // number | boolean | string ) : string
>typeof x === "number" : boolean
>typeof x : string
>x : number | string | boolean
>"number" : string
? (
>( // change value of x x = 10 && x.toString() // number | boolean | string ) : string
// change value of x
x = 10 && x.toString() // number | boolean | string
>x = 10 && x.toString() : string
>x : number | string | boolean
>10 && x.toString() : string
>10 : number
>x.toString() : string
>x.toString : ((radix?: number) => string) | (() => string)
>x : number | string | boolean
>toString : ((radix?: number) => string) | (() => string)
)
: (
>( // do not change value y = x && x.toString() // number | boolean | string ) : string
// do not change value
y = x && x.toString() // number | boolean | string
>y = x && x.toString() : string
>y : number | boolean | string
>x && x.toString() : string
>x : number | string | boolean
>x.toString() : string
>x.toString : ((radix?: number) => string) | (() => string)
>x : number | string | boolean
>toString : ((radix?: number) => string) | (() => string)
);
}
}
function foo12(x: number | string | boolean) {
>foo12 : (x: number | string | boolean) => string
>x : number | string | boolean
// Mixing typeguard narrowing in if statement with conditional expression typeguard
// Assigning value to x in outer guard shouldn't stop narrowing in the inner expression
if (typeof x === "string") {
>typeof x === "string" : boolean
>typeof x : string
>x : number | string | boolean
>"string" : string
return x.toString(); // string | number | boolean - x changed in else branch
>x.toString() : string
>x.toString : ((radix?: number) => string) | (() => string)
>x : number | string | boolean
>toString : ((radix?: number) => string) | (() => string)
}
else {
x = 10;
>x = 10 : number
>x : number | string | boolean
>10 : number
var b = x; // number | boolean | string
>b : number | string | boolean
>x : number | string | boolean
return typeof x === "number"
>typeof x === "number" ? x.toString() // number : x.toString() : string
>typeof x === "number" : boolean
>typeof x : string
>x : number | string | boolean
>"number" : string
? x.toString() // number
>x.toString() : string
>x.toString : (radix?: number) => string
>x : number
>toString : (radix?: number) => string
: x.toString(); // boolean | string
>x.toString() : string
>x.toString : () => string
>x : string | boolean
>toString : () => string
}
}
@@ -1,64 +0,0 @@
tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfAndAndOperator.ts(43,22): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfAndAndOperator.ts(45,21): error TS2349: Cannot invoke an expression whose type lacks a call signature.
==== tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfAndAndOperator.ts (2 errors) ====
// In the right operand of a && operation,
// the type of a variable or parameter is narrowed by any type guard in the left operand when true,
// provided the right operand contains no assignments to the variable or parameter.
function foo(x: number | string) {
return typeof x === "string" && x.length === 10; // string
}
function foo2(x: number | string) {
// modify x in right hand operand
return typeof x === "string" && ((x = 10) && x); // string | number
}
function foo3(x: number | string) {
// modify x in right hand operand with string type itself
return typeof x === "string" && ((x = "hello") && x); // string | number
}
function foo4(x: number | string | boolean) {
return typeof x !== "string" // string | number | boolean
&& typeof x !== "number" // number | boolean
&& x; // boolean
}
function foo5(x: number | string | boolean) {
// usage of x or assignment to separate variable shouldn't cause narrowing of type to stop
var b: number | boolean;
return typeof x !== "string" // string | number | boolean
&& ((b = x) && (typeof x !== "number" // number | boolean
&& x)); // boolean
}
function foo6(x: number | string | boolean) {
// Mixing typeguard narrowing in if statement with conditional expression typeguard
return typeof x !== "string" // string | number | boolean
&& (typeof x !== "number" // number | boolean
? x // boolean
: x === 10) // number
}
function foo7(x: number | string | boolean) {
var y: number| boolean | string;
var z: number| boolean | string;
// Mixing typeguard narrowing
// Assigning value to x deep inside another guard stops narrowing of type too
return typeof x !== "string"
&& ((z = x) // string | number | boolean - x changed deeper in conditional expression
&& (typeof x === "number"
// change value of x
? (x = 10 && x.toString()) // number | boolean | string
~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
// do not change value
: (y = x && x.toString()))); // number | boolean | string
~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
}
function foo8(x: number | string) {
// Mixing typeguard
// Assigning value to x in outer guard shouldn't stop narrowing in the inner expression
return typeof x !== "string"
&& (x = 10) // change x - number| string
&& (typeof x === "number"
? x // number
: x.length); // string
}
@@ -0,0 +1,143 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfAndAndOperator.ts ===
// In the right operand of a && operation,
// the type of a variable or parameter is narrowed by any type guard in the left operand when true,
// provided the right operand contains no assignments to the variable or parameter.
function foo(x: number | string) {
>foo : Symbol(foo, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 0, 0))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 3, 13))
return typeof x === "string" && x.length === 10; // string
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 3, 13))
>x.length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 3, 13))
>length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
}
function foo2(x: number | string) {
>foo2 : Symbol(foo2, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 5, 1))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 6, 14))
// modify x in right hand operand
return typeof x === "string" && ((x = 10) && x); // string | number
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 6, 14))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 6, 14))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 6, 14))
}
function foo3(x: number | string) {
>foo3 : Symbol(foo3, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 9, 1))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 10, 14))
// modify x in right hand operand with string type itself
return typeof x === "string" && ((x = "hello") && x); // string | number
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 10, 14))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 10, 14))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 10, 14))
}
function foo4(x: number | string | boolean) {
>foo4 : Symbol(foo4, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 13, 1))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 14, 14))
return typeof x !== "string" // string | number | boolean
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 14, 14))
&& typeof x !== "number" // number | boolean
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 14, 14))
&& x; // boolean
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 14, 14))
}
function foo5(x: number | string | boolean) {
>foo5 : Symbol(foo5, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 18, 1))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 19, 14))
// usage of x or assignment to separate variable shouldn't cause narrowing of type to stop
var b: number | boolean;
>b : Symbol(b, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 21, 7))
return typeof x !== "string" // string | number | boolean
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 19, 14))
&& ((b = x) && (typeof x !== "number" // number | boolean
>b : Symbol(b, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 21, 7))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 19, 14))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 19, 14))
&& x)); // boolean
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 19, 14))
}
function foo6(x: number | string | boolean) {
>foo6 : Symbol(foo6, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 25, 1))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 26, 14))
// Mixing typeguard narrowing in if statement with conditional expression typeguard
return typeof x !== "string" // string | number | boolean
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 26, 14))
&& (typeof x !== "number" // number | boolean
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 26, 14))
? x // boolean
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 26, 14))
: x === 10) // number
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 26, 14))
}
function foo7(x: number | string | boolean) {
>foo7 : Symbol(foo7, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 32, 1))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 33, 14))
var y: number| boolean | string;
>y : Symbol(y, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 34, 7))
var z: number| boolean | string;
>z : Symbol(z, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 35, 7))
// Mixing typeguard narrowing
// Assigning value to x deep inside another guard stops narrowing of type too
return typeof x !== "string"
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 33, 14))
&& ((z = x) // string | number | boolean - x changed deeper in conditional expression
>z : Symbol(z, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 35, 7))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 33, 14))
&& (typeof x === "number"
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 33, 14))
// change value of x
? (x = 10 && x.toString()) // number | boolean | string
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 33, 14))
>x.toString : Symbol(toString, Decl(lib.d.ts, 458, 18), Decl(lib.d.ts, 277, 18), Decl(lib.d.ts, 96, 26))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 33, 14))
>toString : Symbol(toString, Decl(lib.d.ts, 458, 18), Decl(lib.d.ts, 277, 18), Decl(lib.d.ts, 96, 26))
// do not change value
: (y = x && x.toString()))); // number | boolean | string
>y : Symbol(y, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 34, 7))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 33, 14))
>x.toString : Symbol(toString, Decl(lib.d.ts, 458, 18), Decl(lib.d.ts, 277, 18), Decl(lib.d.ts, 96, 26))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 33, 14))
>toString : Symbol(toString, Decl(lib.d.ts, 458, 18), Decl(lib.d.ts, 277, 18), Decl(lib.d.ts, 96, 26))
}
function foo8(x: number | string) {
>foo8 : Symbol(foo8, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 45, 1))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 46, 14))
// Mixing typeguard
// Assigning value to x in outer guard shouldn't stop narrowing in the inner expression
return typeof x !== "string"
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 46, 14))
&& (x = 10) // change x - number| string
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 46, 14))
&& (typeof x === "number"
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 46, 14))
? x // number
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 46, 14))
: x.length); // string
>x.length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfAndAndOperator.ts, 46, 14))
>length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
}
@@ -0,0 +1,234 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfAndAndOperator.ts ===
// In the right operand of a && operation,
// the type of a variable or parameter is narrowed by any type guard in the left operand when true,
// provided the right operand contains no assignments to the variable or parameter.
function foo(x: number | string) {
>foo : (x: number | string) => boolean
>x : number | string
return typeof x === "string" && x.length === 10; // string
>typeof x === "string" && x.length === 10 : boolean
>typeof x === "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
>x.length === 10 : boolean
>x.length : number
>x : string
>length : number
>10 : number
}
function foo2(x: number | string) {
>foo2 : (x: number | string) => number | string
>x : number | string
// modify x in right hand operand
return typeof x === "string" && ((x = 10) && x); // string | number
>typeof x === "string" && ((x = 10) && x) : number | string
>typeof x === "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
>((x = 10) && x) : number | string
>(x = 10) && x : number | string
>(x = 10) : number
>x = 10 : number
>x : number | string
>10 : number
>x : number | string
}
function foo3(x: number | string) {
>foo3 : (x: number | string) => number | string
>x : number | string
// modify x in right hand operand with string type itself
return typeof x === "string" && ((x = "hello") && x); // string | number
>typeof x === "string" && ((x = "hello") && x) : number | string
>typeof x === "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
>((x = "hello") && x) : number | string
>(x = "hello") && x : number | string
>(x = "hello") : string
>x = "hello" : string
>x : number | string
>"hello" : string
>x : number | string
}
function foo4(x: number | string | boolean) {
>foo4 : (x: number | string | boolean) => boolean
>x : number | string | boolean
return typeof x !== "string" // string | number | boolean
>typeof x !== "string" // string | number | boolean && typeof x !== "number" // number | boolean && x : boolean
>typeof x !== "string" // string | number | boolean && typeof x !== "number" : boolean
>typeof x !== "string" : boolean
>typeof x : string
>x : number | string | boolean
>"string" : string
&& typeof x !== "number" // number | boolean
>typeof x !== "number" : boolean
>typeof x : string
>x : number | boolean
>"number" : string
&& x; // boolean
>x : boolean
}
function foo5(x: number | string | boolean) {
>foo5 : (x: number | string | boolean) => boolean
>x : number | string | boolean
// usage of x or assignment to separate variable shouldn't cause narrowing of type to stop
var b: number | boolean;
>b : number | boolean
return typeof x !== "string" // string | number | boolean
>typeof x !== "string" // string | number | boolean && ((b = x) && (typeof x !== "number" // number | boolean && x)) : boolean
>typeof x !== "string" : boolean
>typeof x : string
>x : number | string | boolean
>"string" : string
&& ((b = x) && (typeof x !== "number" // number | boolean
>((b = x) && (typeof x !== "number" // number | boolean && x)) : boolean
>(b = x) && (typeof x !== "number" // number | boolean && x) : boolean
>(b = x) : number | boolean
>b = x : number | boolean
>b : number | boolean
>x : number | boolean
>(typeof x !== "number" // number | boolean && x) : boolean
>typeof x !== "number" // number | boolean && x : boolean
>typeof x !== "number" : boolean
>typeof x : string
>x : number | boolean
>"number" : string
&& x)); // boolean
>x : boolean
}
function foo6(x: number | string | boolean) {
>foo6 : (x: number | string | boolean) => boolean
>x : number | string | boolean
// Mixing typeguard narrowing in if statement with conditional expression typeguard
return typeof x !== "string" // string | number | boolean
>typeof x !== "string" // string | number | boolean && (typeof x !== "number" // number | boolean ? x // boolean : x === 10) : boolean
>typeof x !== "string" : boolean
>typeof x : string
>x : number | string | boolean
>"string" : string
&& (typeof x !== "number" // number | boolean
>(typeof x !== "number" // number | boolean ? x // boolean : x === 10) : boolean
>typeof x !== "number" // number | boolean ? x // boolean : x === 10 : boolean
>typeof x !== "number" : boolean
>typeof x : string
>x : number | boolean
>"number" : string
? x // boolean
>x : boolean
: x === 10) // number
>x === 10 : boolean
>x : number
>10 : number
}
function foo7(x: number | string | boolean) {
>foo7 : (x: number | string | boolean) => string
>x : number | string | boolean
var y: number| boolean | string;
>y : number | boolean | string
var z: number| boolean | string;
>z : number | boolean | string
// Mixing typeguard narrowing
// Assigning value to x deep inside another guard stops narrowing of type too
return typeof x !== "string"
>typeof x !== "string" && ((z = x) // string | number | boolean - x changed deeper in conditional expression && (typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString()))) : string
>typeof x !== "string" : boolean
>typeof x : string
>x : number | string | boolean
>"string" : string
&& ((z = x) // string | number | boolean - x changed deeper in conditional expression
>((z = x) // string | number | boolean - x changed deeper in conditional expression && (typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString()))) : string
>(z = x) // string | number | boolean - x changed deeper in conditional expression && (typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString())) : string
>(z = x) : number | string | boolean
>z = x : number | string | boolean
>z : number | boolean | string
>x : number | string | boolean
&& (typeof x === "number"
>(typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString())) : string
>typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString()) : string
>typeof x === "number" : boolean
>typeof x : string
>x : number | string | boolean
>"number" : string
// change value of x
? (x = 10 && x.toString()) // number | boolean | string
>(x = 10 && x.toString()) : string
>x = 10 && x.toString() : string
>x : number | string | boolean
>10 && x.toString() : string
>10 : number
>x.toString() : string
>x.toString : ((radix?: number) => string) | (() => string)
>x : number | string | boolean
>toString : ((radix?: number) => string) | (() => string)
// do not change value
: (y = x && x.toString()))); // number | boolean | string
>(y = x && x.toString()) : string
>y = x && x.toString() : string
>y : number | boolean | string
>x && x.toString() : string
>x : number | string | boolean
>x.toString() : string
>x.toString : ((radix?: number) => string) | (() => string)
>x : number | string | boolean
>toString : ((radix?: number) => string) | (() => string)
}
function foo8(x: number | string) {
>foo8 : (x: number | string) => number
>x : number | string
// Mixing typeguard
// Assigning value to x in outer guard shouldn't stop narrowing in the inner expression
return typeof x !== "string"
>typeof x !== "string" && (x = 10) // change x - number| string && (typeof x === "number" ? x // number : x.length) : number
>typeof x !== "string" && (x = 10) : number
>typeof x !== "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
&& (x = 10) // change x - number| string
>(x = 10) : number
>x = 10 : number
>x : number | string
>10 : number
&& (typeof x === "number"
>(typeof x === "number" ? x // number : x.length) : number
>typeof x === "number" ? x // number : x.length : number
>typeof x === "number" : boolean
>typeof x : string
>x : number | string
>"number" : string
? x // number
>x : number
: x.length); // string
>x.length : number
>x : string
>length : number
}
@@ -1,64 +0,0 @@
tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfOrOrOperator.ts(43,22): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfOrOrOperator.ts(45,21): error TS2349: Cannot invoke an expression whose type lacks a call signature.
==== tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfOrOrOperator.ts (2 errors) ====
// In the right operand of a || operation,
// the type of a variable or parameter is narrowed by any type guard in the left operand when false,
// provided the right operand contains no assignments to the variable or parameter.
function foo(x: number | string) {
return typeof x !== "string" || x.length === 10; // string
}
function foo2(x: number | string) {
// modify x in right hand operand
return typeof x !== "string" || ((x = 10) || x); // string | number
}
function foo3(x: number | string) {
// modify x in right hand operand with string type itself
return typeof x !== "string" || ((x = "hello") || x); // string | number
}
function foo4(x: number | string | boolean) {
return typeof x === "string" // string | number | boolean
|| typeof x === "number" // number | boolean
|| x; // boolean
}
function foo5(x: number | string | boolean) {
// usage of x or assignment to separate variable shouldn't cause narrowing of type to stop
var b: number | boolean;
return typeof x === "string" // string | number | boolean
|| ((b = x) || (typeof x === "number" // number | boolean
|| x)); // boolean
}
function foo6(x: number | string | boolean) {
// Mixing typeguard
return typeof x === "string" // string | number | boolean
|| (typeof x !== "number" // number | boolean
? x // boolean
: x === 10) // number
}
function foo7(x: number | string | boolean) {
var y: number| boolean | string;
var z: number| boolean | string;
// Mixing typeguard narrowing
// Assigning value to x deep inside another guard stops narrowing of type too
return typeof x === "string"
|| ((z = x) // string | number | boolean - x changed deeper in conditional expression
|| (typeof x === "number"
// change value of x
? (x = 10 && x.toString()) // number | boolean | string
~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
// do not change value
: (y = x && x.toString()))); // number | boolean | string
~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
}
function foo8(x: number | string) {
// Mixing typeguard
// Assigning value to x in outer guard shouldn't stop narrowing in the inner expression
return typeof x === "string"
|| (x = 10) // change x - number| string
|| (typeof x === "number"
? x // number
: x.length); // string
}
@@ -0,0 +1,143 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfOrOrOperator.ts ===
// In the right operand of a || operation,
// the type of a variable or parameter is narrowed by any type guard in the left operand when false,
// provided the right operand contains no assignments to the variable or parameter.
function foo(x: number | string) {
>foo : Symbol(foo, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 0, 0))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 3, 13))
return typeof x !== "string" || x.length === 10; // string
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 3, 13))
>x.length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 3, 13))
>length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
}
function foo2(x: number | string) {
>foo2 : Symbol(foo2, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 5, 1))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 6, 14))
// modify x in right hand operand
return typeof x !== "string" || ((x = 10) || x); // string | number
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 6, 14))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 6, 14))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 6, 14))
}
function foo3(x: number | string) {
>foo3 : Symbol(foo3, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 9, 1))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 10, 14))
// modify x in right hand operand with string type itself
return typeof x !== "string" || ((x = "hello") || x); // string | number
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 10, 14))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 10, 14))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 10, 14))
}
function foo4(x: number | string | boolean) {
>foo4 : Symbol(foo4, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 13, 1))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 14, 14))
return typeof x === "string" // string | number | boolean
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 14, 14))
|| typeof x === "number" // number | boolean
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 14, 14))
|| x; // boolean
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 14, 14))
}
function foo5(x: number | string | boolean) {
>foo5 : Symbol(foo5, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 18, 1))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 19, 14))
// usage of x or assignment to separate variable shouldn't cause narrowing of type to stop
var b: number | boolean;
>b : Symbol(b, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 21, 7))
return typeof x === "string" // string | number | boolean
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 19, 14))
|| ((b = x) || (typeof x === "number" // number | boolean
>b : Symbol(b, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 21, 7))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 19, 14))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 19, 14))
|| x)); // boolean
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 19, 14))
}
function foo6(x: number | string | boolean) {
>foo6 : Symbol(foo6, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 25, 1))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 26, 14))
// Mixing typeguard
return typeof x === "string" // string | number | boolean
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 26, 14))
|| (typeof x !== "number" // number | boolean
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 26, 14))
? x // boolean
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 26, 14))
: x === 10) // number
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 26, 14))
}
function foo7(x: number | string | boolean) {
>foo7 : Symbol(foo7, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 32, 1))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 33, 14))
var y: number| boolean | string;
>y : Symbol(y, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 34, 7))
var z: number| boolean | string;
>z : Symbol(z, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 35, 7))
// Mixing typeguard narrowing
// Assigning value to x deep inside another guard stops narrowing of type too
return typeof x === "string"
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 33, 14))
|| ((z = x) // string | number | boolean - x changed deeper in conditional expression
>z : Symbol(z, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 35, 7))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 33, 14))
|| (typeof x === "number"
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 33, 14))
// change value of x
? (x = 10 && x.toString()) // number | boolean | string
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 33, 14))
>x.toString : Symbol(toString, Decl(lib.d.ts, 458, 18), Decl(lib.d.ts, 277, 18), Decl(lib.d.ts, 96, 26))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 33, 14))
>toString : Symbol(toString, Decl(lib.d.ts, 458, 18), Decl(lib.d.ts, 277, 18), Decl(lib.d.ts, 96, 26))
// do not change value
: (y = x && x.toString()))); // number | boolean | string
>y : Symbol(y, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 34, 7))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 33, 14))
>x.toString : Symbol(toString, Decl(lib.d.ts, 458, 18), Decl(lib.d.ts, 277, 18), Decl(lib.d.ts, 96, 26))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 33, 14))
>toString : Symbol(toString, Decl(lib.d.ts, 458, 18), Decl(lib.d.ts, 277, 18), Decl(lib.d.ts, 96, 26))
}
function foo8(x: number | string) {
>foo8 : Symbol(foo8, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 45, 1))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 46, 14))
// Mixing typeguard
// Assigning value to x in outer guard shouldn't stop narrowing in the inner expression
return typeof x === "string"
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 46, 14))
|| (x = 10) // change x - number| string
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 46, 14))
|| (typeof x === "number"
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 46, 14))
? x // number
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 46, 14))
: x.length); // string
>x.length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
>x : Symbol(x, Decl(typeGuardsInRightOperandOfOrOrOperator.ts, 46, 14))
>length : Symbol(String.length, Decl(lib.d.ts, 414, 19))
}
@@ -0,0 +1,234 @@
=== tests/cases/conformance/expressions/typeGuards/typeGuardsInRightOperandOfOrOrOperator.ts ===
// In the right operand of a || operation,
// the type of a variable or parameter is narrowed by any type guard in the left operand when false,
// provided the right operand contains no assignments to the variable or parameter.
function foo(x: number | string) {
>foo : (x: number | string) => boolean
>x : number | string
return typeof x !== "string" || x.length === 10; // string
>typeof x !== "string" || x.length === 10 : boolean
>typeof x !== "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
>x.length === 10 : boolean
>x.length : number
>x : string
>length : number
>10 : number
}
function foo2(x: number | string) {
>foo2 : (x: number | string) => boolean | number | string
>x : number | string
// modify x in right hand operand
return typeof x !== "string" || ((x = 10) || x); // string | number
>typeof x !== "string" || ((x = 10) || x) : boolean | number | string
>typeof x !== "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
>((x = 10) || x) : number | string
>(x = 10) || x : number | string
>(x = 10) : number
>x = 10 : number
>x : number | string
>10 : number
>x : number | string
}
function foo3(x: number | string) {
>foo3 : (x: number | string) => boolean | string | number
>x : number | string
// modify x in right hand operand with string type itself
return typeof x !== "string" || ((x = "hello") || x); // string | number
>typeof x !== "string" || ((x = "hello") || x) : boolean | string | number
>typeof x !== "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
>((x = "hello") || x) : string | number
>(x = "hello") || x : string | number
>(x = "hello") : string
>x = "hello" : string
>x : number | string
>"hello" : string
>x : number | string
}
function foo4(x: number | string | boolean) {
>foo4 : (x: number | string | boolean) => boolean
>x : number | string | boolean
return typeof x === "string" // string | number | boolean
>typeof x === "string" // string | number | boolean || typeof x === "number" // number | boolean || x : boolean
>typeof x === "string" // string | number | boolean || typeof x === "number" : boolean
>typeof x === "string" : boolean
>typeof x : string
>x : number | string | boolean
>"string" : string
|| typeof x === "number" // number | boolean
>typeof x === "number" : boolean
>typeof x : string
>x : number | boolean
>"number" : string
|| x; // boolean
>x : boolean
}
function foo5(x: number | string | boolean) {
>foo5 : (x: number | string | boolean) => boolean | number
>x : number | string | boolean
// usage of x or assignment to separate variable shouldn't cause narrowing of type to stop
var b: number | boolean;
>b : number | boolean
return typeof x === "string" // string | number | boolean
>typeof x === "string" // string | number | boolean || ((b = x) || (typeof x === "number" // number | boolean || x)) : boolean | number
>typeof x === "string" : boolean
>typeof x : string
>x : number | string | boolean
>"string" : string
|| ((b = x) || (typeof x === "number" // number | boolean
>((b = x) || (typeof x === "number" // number | boolean || x)) : number | boolean
>(b = x) || (typeof x === "number" // number | boolean || x) : number | boolean
>(b = x) : number | boolean
>b = x : number | boolean
>b : number | boolean
>x : number | boolean
>(typeof x === "number" // number | boolean || x) : boolean
>typeof x === "number" // number | boolean || x : boolean
>typeof x === "number" : boolean
>typeof x : string
>x : number | boolean
>"number" : string
|| x)); // boolean
>x : boolean
}
function foo6(x: number | string | boolean) {
>foo6 : (x: number | string | boolean) => boolean
>x : number | string | boolean
// Mixing typeguard
return typeof x === "string" // string | number | boolean
>typeof x === "string" // string | number | boolean || (typeof x !== "number" // number | boolean ? x // boolean : x === 10) : boolean
>typeof x === "string" : boolean
>typeof x : string
>x : number | string | boolean
>"string" : string
|| (typeof x !== "number" // number | boolean
>(typeof x !== "number" // number | boolean ? x // boolean : x === 10) : boolean
>typeof x !== "number" // number | boolean ? x // boolean : x === 10 : boolean
>typeof x !== "number" : boolean
>typeof x : string
>x : number | boolean
>"number" : string
? x // boolean
>x : boolean
: x === 10) // number
>x === 10 : boolean
>x : number
>10 : number
}
function foo7(x: number | string | boolean) {
>foo7 : (x: number | string | boolean) => boolean | number | string
>x : number | string | boolean
var y: number| boolean | string;
>y : number | boolean | string
var z: number| boolean | string;
>z : number | boolean | string
// Mixing typeguard narrowing
// Assigning value to x deep inside another guard stops narrowing of type too
return typeof x === "string"
>typeof x === "string" || ((z = x) // string | number | boolean - x changed deeper in conditional expression || (typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString()))) : boolean | number | string
>typeof x === "string" : boolean
>typeof x : string
>x : number | string | boolean
>"string" : string
|| ((z = x) // string | number | boolean - x changed deeper in conditional expression
>((z = x) // string | number | boolean - x changed deeper in conditional expression || (typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString()))) : number | string | boolean
>(z = x) // string | number | boolean - x changed deeper in conditional expression || (typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString())) : number | string | boolean
>(z = x) : number | string | boolean
>z = x : number | string | boolean
>z : number | boolean | string
>x : number | string | boolean
|| (typeof x === "number"
>(typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString())) : string
>typeof x === "number" // change value of x ? (x = 10 && x.toString()) // number | boolean | string // do not change value : (y = x && x.toString()) : string
>typeof x === "number" : boolean
>typeof x : string
>x : number | string | boolean
>"number" : string
// change value of x
? (x = 10 && x.toString()) // number | boolean | string
>(x = 10 && x.toString()) : string
>x = 10 && x.toString() : string
>x : number | string | boolean
>10 && x.toString() : string
>10 : number
>x.toString() : string
>x.toString : ((radix?: number) => string) | (() => string)
>x : number | string | boolean
>toString : ((radix?: number) => string) | (() => string)
// do not change value
: (y = x && x.toString()))); // number | boolean | string
>(y = x && x.toString()) : string
>y = x && x.toString() : string
>y : number | boolean | string
>x && x.toString() : string
>x : number | string | boolean
>x.toString() : string
>x.toString : ((radix?: number) => string) | (() => string)
>x : number | string | boolean
>toString : ((radix?: number) => string) | (() => string)
}
function foo8(x: number | string) {
>foo8 : (x: number | string) => boolean | number
>x : number | string
// Mixing typeguard
// Assigning value to x in outer guard shouldn't stop narrowing in the inner expression
return typeof x === "string"
>typeof x === "string" || (x = 10) // change x - number| string || (typeof x === "number" ? x // number : x.length) : boolean | number
>typeof x === "string" || (x = 10) : boolean | number
>typeof x === "string" : boolean
>typeof x : string
>x : number | string
>"string" : string
|| (x = 10) // change x - number| string
>(x = 10) : number
>x = 10 : number
>x : number | string
>10 : number
|| (typeof x === "number"
>(typeof x === "number" ? x // number : x.length) : number
>typeof x === "number" ? x // number : x.length : number
>typeof x === "number" : boolean
>typeof x : string
>x : number | string
>"number" : string
? x // number
>x : number
: x.length); // string
>x.length : number
>x : string
>length : number
}
@@ -12,29 +12,25 @@ tests/cases/conformance/types/union/unionTypeCallSignatures.ts(30,1): error TS23
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(31,1): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(36,49): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(37,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(40,12): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(41,12): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(42,12): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(43,12): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(46,12): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(47,12): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(48,12): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(49,12): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(40,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(42,49): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(43,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(47,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(48,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(49,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(55,45): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(56,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(59,12): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(60,12): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(61,12): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(62,12): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(63,12): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(66,12): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(67,12): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(68,12): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(69,12): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(70,12): error TS2349: Cannot invoke an expression whose type lacks a call signature.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(59,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(61,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(62,45): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(63,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(67,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(68,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(69,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeCallSignatures.ts(70,12): error TS2346: Supplied parameters do not match any signature of call target.
==== tests/cases/conformance/types/union/unionTypeCallSignatures.ts (34 errors) ====
==== tests/cases/conformance/types/union/unionTypeCallSignatures.ts (30 errors) ====
var numOrDate: number | Date;
var strOrBoolean: string | boolean;
var strOrNum: string | number;
@@ -80,7 +76,7 @@ tests/cases/conformance/types/union/unionTypeCallSignatures.ts(70,12): error TS2
~~~~~~~
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
var unionWithDifferentParameterCount: { (a: string): string; } | { (a: string, b: number): number; } ;
var unionWithDifferentParameterCount: { (a: string): string; } | { (a: string, b: number): number; } ;
unionWithDifferentParameterCount();// no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
@@ -91,7 +87,7 @@ tests/cases/conformance/types/union/unionTypeCallSignatures.ts(70,12): error TS2
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
var unionWithOptionalParameter1: { (a: string, b?: number): string; } | { (a: string, b?: number): number; };
var unionWithOptionalParameter1: { (a: string, b?: number): string; } | { (a: string, b?: number): number; };
strOrNum = unionWithOptionalParameter1('hello');
strOrNum = unionWithOptionalParameter1('hello', 10);
strOrNum = unionWithOptionalParameter1('hello', "hello"); // error in parameter type
@@ -104,30 +100,26 @@ tests/cases/conformance/types/union/unionTypeCallSignatures.ts(70,12): error TS2
var unionWithOptionalParameter2: { (a: string, b?: number): string; } | { (a: string, b: number): number };
strOrNum = unionWithOptionalParameter2('hello'); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
strOrNum = unionWithOptionalParameter2('hello', 10); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
strOrNum = unionWithOptionalParameter2('hello', "hello"); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
~~~~~~~
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
strOrNum = unionWithOptionalParameter2(); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
var unionWithOptionalParameter3: { (a: string, b?: number): string; } | { (a: string): number; };
strOrNum = unionWithOptionalParameter3('hello'); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
strOrNum = unionWithOptionalParameter3('hello');
strOrNum = unionWithOptionalParameter3('hello', 10); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
strOrNum = unionWithOptionalParameter3('hello', "hello"); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
strOrNum = unionWithOptionalParameter3(); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
var unionWithRestParameter1: { (a: string, ...b: number[]): string; } | { (a: string, ...b: number[]): number };
strOrNum = unionWithRestParameter1('hello');
@@ -143,33 +135,31 @@ tests/cases/conformance/types/union/unionTypeCallSignatures.ts(70,12): error TS2
var unionWithRestParameter2: { (a: string, ...b: number[]): string; } | { (a: string, b: number): number };
strOrNum = unionWithRestParameter2('hello'); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
strOrNum = unionWithRestParameter2('hello', 10); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
strOrNum = unionWithRestParameter2('hello', 10, 11); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
strOrNum = unionWithRestParameter2('hello', "hello"); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
~~~~~~~
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
strOrNum = unionWithRestParameter2(); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
var unionWithRestParameter3: { (a: string, ...b: number[]): string; } | { (a: string): number };
strOrNum = unionWithRestParameter3('hello'); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
strOrNum = unionWithRestParameter3('hello');
strOrNum = unionWithRestParameter3('hello', 10); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
strOrNum = unionWithRestParameter3('hello', 10, 11); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
strOrNum = unionWithRestParameter3('hello', "hello"); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
strOrNum = unionWithRestParameter3(); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2349: Cannot invoke an expression whose type lacks a call signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
@@ -26,12 +26,12 @@ unionOfDifferentNumberOfSignatures(); // error - no call signatures
unionOfDifferentNumberOfSignatures(10); // error - no call signatures
unionOfDifferentNumberOfSignatures("hello"); // error - no call signatures
var unionWithDifferentParameterCount: { (a: string): string; } | { (a: string, b: number): number; } ;
var unionWithDifferentParameterCount: { (a: string): string; } | { (a: string, b: number): number; } ;
unionWithDifferentParameterCount();// no call signature
unionWithDifferentParameterCount("hello");// no call signature
unionWithDifferentParameterCount("hello", 10);// no call signature
var unionWithOptionalParameter1: { (a: string, b?: number): string; } | { (a: string, b?: number): number; };
var unionWithOptionalParameter1: { (a: string, b?: number): string; } | { (a: string, b?: number): number; };
strOrNum = unionWithOptionalParameter1('hello');
strOrNum = unionWithOptionalParameter1('hello', 10);
strOrNum = unionWithOptionalParameter1('hello', "hello"); // error in parameter type
@@ -44,7 +44,7 @@ strOrNum = unionWithOptionalParameter2('hello', "hello"); // error no call signa
strOrNum = unionWithOptionalParameter2(); // error no call signature
var unionWithOptionalParameter3: { (a: string, b?: number): string; } | { (a: string): number; };
strOrNum = unionWithOptionalParameter3('hello'); // error no call signature
strOrNum = unionWithOptionalParameter3('hello');
strOrNum = unionWithOptionalParameter3('hello', 10); // error no call signature
strOrNum = unionWithOptionalParameter3('hello', "hello"); // error no call signature
strOrNum = unionWithOptionalParameter3(); // error no call signature
@@ -64,11 +64,13 @@ strOrNum = unionWithRestParameter2('hello', "hello"); // error no call signature
strOrNum = unionWithRestParameter2(); // error no call signature
var unionWithRestParameter3: { (a: string, ...b: number[]): string; } | { (a: string): number };
strOrNum = unionWithRestParameter3('hello'); // error no call signature
strOrNum = unionWithRestParameter3('hello');
strOrNum = unionWithRestParameter3('hello', 10); // error no call signature
strOrNum = unionWithRestParameter3('hello', 10, 11); // error no call signature
strOrNum = unionWithRestParameter3('hello', "hello"); // error no call signature
strOrNum = unionWithRestParameter3(); // error no call signature
strOrNum = unionWithRestParameter3(); // error no call signature
//// [unionTypeCallSignatures.js]
var numOrDate;
@@ -108,7 +110,7 @@ strOrNum = unionWithOptionalParameter2('hello', 10); // error no call signature
strOrNum = unionWithOptionalParameter2('hello', "hello"); // error no call signature
strOrNum = unionWithOptionalParameter2(); // error no call signature
var unionWithOptionalParameter3;
strOrNum = unionWithOptionalParameter3('hello'); // error no call signature
strOrNum = unionWithOptionalParameter3('hello');
strOrNum = unionWithOptionalParameter3('hello', 10); // error no call signature
strOrNum = unionWithOptionalParameter3('hello', "hello"); // error no call signature
strOrNum = unionWithOptionalParameter3(); // error no call signature
@@ -125,7 +127,7 @@ strOrNum = unionWithRestParameter2('hello', 10, 11); // error no call signature
strOrNum = unionWithRestParameter2('hello', "hello"); // error no call signature
strOrNum = unionWithRestParameter2(); // error no call signature
var unionWithRestParameter3;
strOrNum = unionWithRestParameter3('hello'); // error no call signature
strOrNum = unionWithRestParameter3('hello');
strOrNum = unionWithRestParameter3('hello', 10); // error no call signature
strOrNum = unionWithRestParameter3('hello', 10, 11); // error no call signature
strOrNum = unionWithRestParameter3('hello', "hello"); // error no call signature
@@ -0,0 +1,51 @@
//// [unionTypeCallSignatures2.ts]
interface A {
(x: number): number;
(x: string, y?: string): boolean;
(x: Date): void;
<T>(x: T[]): T[];
}
interface B {
(x: number): number;
(x: string): string;
(x: Date): void;
<T>(x: T[]): T[];
}
interface C {
(x: string, ...y: string[]): number;
(x: number, s?: string): number;
<T>(x: T[]): T[];
}
var f1: A | B | C;
var n1 = f1(42); // number
var s1 = f1("abc"); // boolean | string | number
var a1 = f1([true, false]); // boolean[]
var f2: C | B | A;
var n2 = f2(42); // number
var s2 = f2("abc"); // number | string | boolean
var a2 = f2([true, false]); // boolean[]
var f3: B | A | C;
var n3 = f3(42); // number
var s3 = f3("abc"); // string | boolean | number
var a3 = f3([true, false]); // boolean[]
//// [unionTypeCallSignatures2.js]
var f1;
var n1 = f1(42); // number
var s1 = f1("abc"); // boolean | string | number
var a1 = f1([true, false]); // boolean[]
var f2;
var n2 = f2(42); // number
var s2 = f2("abc"); // number | string | boolean
var a2 = f2([true, false]); // boolean[]
var f3;
var n3 = f3(42); // number
var s3 = f3("abc"); // string | boolean | number
var a3 = f3([true, false]); // boolean[]
@@ -0,0 +1,115 @@
=== tests/cases/conformance/types/union/unionTypeCallSignatures2.ts ===
interface A {
>A : Symbol(A, Decl(unionTypeCallSignatures2.ts, 0, 0))
(x: number): number;
>x : Symbol(x, Decl(unionTypeCallSignatures2.ts, 1, 5))
(x: string, y?: string): boolean;
>x : Symbol(x, Decl(unionTypeCallSignatures2.ts, 2, 5))
>y : Symbol(y, Decl(unionTypeCallSignatures2.ts, 2, 15))
(x: Date): void;
>x : Symbol(x, Decl(unionTypeCallSignatures2.ts, 3, 5))
>Date : Symbol(Date, Decl(lib.d.ts, 633, 23), Decl(lib.d.ts, 815, 11))
<T>(x: T[]): T[];
>T : Symbol(T, Decl(unionTypeCallSignatures2.ts, 4, 5))
>x : Symbol(x, Decl(unionTypeCallSignatures2.ts, 4, 8))
>T : Symbol(T, Decl(unionTypeCallSignatures2.ts, 4, 5))
>T : Symbol(T, Decl(unionTypeCallSignatures2.ts, 4, 5))
}
interface B {
>B : Symbol(B, Decl(unionTypeCallSignatures2.ts, 5, 1))
(x: number): number;
>x : Symbol(x, Decl(unionTypeCallSignatures2.ts, 8, 5))
(x: string): string;
>x : Symbol(x, Decl(unionTypeCallSignatures2.ts, 9, 5))
(x: Date): void;
>x : Symbol(x, Decl(unionTypeCallSignatures2.ts, 10, 5))
>Date : Symbol(Date, Decl(lib.d.ts, 633, 23), Decl(lib.d.ts, 815, 11))
<T>(x: T[]): T[];
>T : Symbol(T, Decl(unionTypeCallSignatures2.ts, 11, 5))
>x : Symbol(x, Decl(unionTypeCallSignatures2.ts, 11, 8))
>T : Symbol(T, Decl(unionTypeCallSignatures2.ts, 11, 5))
>T : Symbol(T, Decl(unionTypeCallSignatures2.ts, 11, 5))
}
interface C {
>C : Symbol(C, Decl(unionTypeCallSignatures2.ts, 12, 1))
(x: string, ...y: string[]): number;
>x : Symbol(x, Decl(unionTypeCallSignatures2.ts, 15, 5))
>y : Symbol(y, Decl(unionTypeCallSignatures2.ts, 15, 15))
(x: number, s?: string): number;
>x : Symbol(x, Decl(unionTypeCallSignatures2.ts, 16, 5))
>s : Symbol(s, Decl(unionTypeCallSignatures2.ts, 16, 15))
<T>(x: T[]): T[];
>T : Symbol(T, Decl(unionTypeCallSignatures2.ts, 17, 5))
>x : Symbol(x, Decl(unionTypeCallSignatures2.ts, 17, 8))
>T : Symbol(T, Decl(unionTypeCallSignatures2.ts, 17, 5))
>T : Symbol(T, Decl(unionTypeCallSignatures2.ts, 17, 5))
}
var f1: A | B | C;
>f1 : Symbol(f1, Decl(unionTypeCallSignatures2.ts, 20, 3))
>A : Symbol(A, Decl(unionTypeCallSignatures2.ts, 0, 0))
>B : Symbol(B, Decl(unionTypeCallSignatures2.ts, 5, 1))
>C : Symbol(C, Decl(unionTypeCallSignatures2.ts, 12, 1))
var n1 = f1(42); // number
>n1 : Symbol(n1, Decl(unionTypeCallSignatures2.ts, 21, 3))
>f1 : Symbol(f1, Decl(unionTypeCallSignatures2.ts, 20, 3))
var s1 = f1("abc"); // boolean | string | number
>s1 : Symbol(s1, Decl(unionTypeCallSignatures2.ts, 22, 3))
>f1 : Symbol(f1, Decl(unionTypeCallSignatures2.ts, 20, 3))
var a1 = f1([true, false]); // boolean[]
>a1 : Symbol(a1, Decl(unionTypeCallSignatures2.ts, 23, 3))
>f1 : Symbol(f1, Decl(unionTypeCallSignatures2.ts, 20, 3))
var f2: C | B | A;
>f2 : Symbol(f2, Decl(unionTypeCallSignatures2.ts, 25, 3))
>C : Symbol(C, Decl(unionTypeCallSignatures2.ts, 12, 1))
>B : Symbol(B, Decl(unionTypeCallSignatures2.ts, 5, 1))
>A : Symbol(A, Decl(unionTypeCallSignatures2.ts, 0, 0))
var n2 = f2(42); // number
>n2 : Symbol(n2, Decl(unionTypeCallSignatures2.ts, 26, 3))
>f2 : Symbol(f2, Decl(unionTypeCallSignatures2.ts, 25, 3))
var s2 = f2("abc"); // number | string | boolean
>s2 : Symbol(s2, Decl(unionTypeCallSignatures2.ts, 27, 3))
>f2 : Symbol(f2, Decl(unionTypeCallSignatures2.ts, 25, 3))
var a2 = f2([true, false]); // boolean[]
>a2 : Symbol(a2, Decl(unionTypeCallSignatures2.ts, 28, 3))
>f2 : Symbol(f2, Decl(unionTypeCallSignatures2.ts, 25, 3))
var f3: B | A | C;
>f3 : Symbol(f3, Decl(unionTypeCallSignatures2.ts, 30, 3))
>B : Symbol(B, Decl(unionTypeCallSignatures2.ts, 5, 1))
>A : Symbol(A, Decl(unionTypeCallSignatures2.ts, 0, 0))
>C : Symbol(C, Decl(unionTypeCallSignatures2.ts, 12, 1))
var n3 = f3(42); // number
>n3 : Symbol(n3, Decl(unionTypeCallSignatures2.ts, 31, 3))
>f3 : Symbol(f3, Decl(unionTypeCallSignatures2.ts, 30, 3))
var s3 = f3("abc"); // string | boolean | number
>s3 : Symbol(s3, Decl(unionTypeCallSignatures2.ts, 32, 3))
>f3 : Symbol(f3, Decl(unionTypeCallSignatures2.ts, 30, 3))
var a3 = f3([true, false]); // boolean[]
>a3 : Symbol(a3, Decl(unionTypeCallSignatures2.ts, 33, 3))
>f3 : Symbol(f3, Decl(unionTypeCallSignatures2.ts, 30, 3))
@@ -0,0 +1,139 @@
=== tests/cases/conformance/types/union/unionTypeCallSignatures2.ts ===
interface A {
>A : A
(x: number): number;
>x : number
(x: string, y?: string): boolean;
>x : string
>y : string
(x: Date): void;
>x : Date
>Date : Date
<T>(x: T[]): T[];
>T : T
>x : T[]
>T : T
>T : T
}
interface B {
>B : B
(x: number): number;
>x : number
(x: string): string;
>x : string
(x: Date): void;
>x : Date
>Date : Date
<T>(x: T[]): T[];
>T : T
>x : T[]
>T : T
>T : T
}
interface C {
>C : C
(x: string, ...y: string[]): number;
>x : string
>y : string[]
(x: number, s?: string): number;
>x : number
>s : string
<T>(x: T[]): T[];
>T : T
>x : T[]
>T : T
>T : T
}
var f1: A | B | C;
>f1 : A | B | C
>A : A
>B : B
>C : C
var n1 = f1(42); // number
>n1 : number
>f1(42) : number
>f1 : A | B | C
>42 : number
var s1 = f1("abc"); // boolean | string | number
>s1 : boolean | string | number
>f1("abc") : boolean | string | number
>f1 : A | B | C
>"abc" : string
var a1 = f1([true, false]); // boolean[]
>a1 : boolean[]
>f1([true, false]) : boolean[]
>f1 : A | B | C
>[true, false] : boolean[]
>true : boolean
>false : boolean
var f2: C | B | A;
>f2 : C | B | A
>C : C
>B : B
>A : A
var n2 = f2(42); // number
>n2 : number
>f2(42) : number
>f2 : C | B | A
>42 : number
var s2 = f2("abc"); // number | string | boolean
>s2 : number | string | boolean
>f2("abc") : number | string | boolean
>f2 : C | B | A
>"abc" : string
var a2 = f2([true, false]); // boolean[]
>a2 : boolean[]
>f2([true, false]) : boolean[]
>f2 : C | B | A
>[true, false] : boolean[]
>true : boolean
>false : boolean
var f3: B | A | C;
>f3 : B | A | C
>B : B
>A : A
>C : C
var n3 = f3(42); // number
>n3 : number
>f3(42) : number
>f3 : B | A | C
>42 : number
var s3 = f3("abc"); // string | boolean | number
>s3 : string | boolean | number
>f3("abc") : string | boolean | number
>f3 : B | A | C
>"abc" : string
var a3 = f3([true, false]); // boolean[]
>a3 : boolean[]
>f3([true, false]) : boolean[]
>f3 : B | A | C
>[true, false] : boolean[]
>true : boolean
>false : boolean
@@ -0,0 +1,39 @@
//// [unionTypeCallSignatures3.ts]
function f1(s: string) { }
function f2(s?: string) { }
function f3(...s: string[]) { }
function f4(s: string, s2?: string) { }
function f5(s?: string, n?: number) { }
function f6(s?: string, ...n: number[]) { }
function f7(s: string, ...sRest: string[]) { }
var fUnion: typeof f1 | typeof f2 | typeof f3 | typeof f4 | typeof f5 | typeof f6 | typeof f7;
fUnion(""); // All constituents can be called by passing a single string.
//// [unionTypeCallSignatures3.js]
function f1(s) { }
function f2(s) { }
function f3() {
var s = [];
for (var _i = 0; _i < arguments.length; _i++) {
s[_i - 0] = arguments[_i];
}
}
function f4(s, s2) { }
function f5(s, n) { }
function f6(s) {
var n = [];
for (var _i = 1; _i < arguments.length; _i++) {
n[_i - 1] = arguments[_i];
}
}
function f7(s) {
var sRest = [];
for (var _i = 1; _i < arguments.length; _i++) {
sRest[_i - 1] = arguments[_i];
}
}
var fUnion;
fUnion(""); // All constituents can be called by passing a single string.
@@ -0,0 +1,46 @@
=== tests/cases/conformance/types/union/unionTypeCallSignatures3.ts ===
function f1(s: string) { }
>f1 : Symbol(f1, Decl(unionTypeCallSignatures3.ts, 0, 0))
>s : Symbol(s, Decl(unionTypeCallSignatures3.ts, 0, 12))
function f2(s?: string) { }
>f2 : Symbol(f2, Decl(unionTypeCallSignatures3.ts, 0, 26))
>s : Symbol(s, Decl(unionTypeCallSignatures3.ts, 1, 12))
function f3(...s: string[]) { }
>f3 : Symbol(f3, Decl(unionTypeCallSignatures3.ts, 1, 27))
>s : Symbol(s, Decl(unionTypeCallSignatures3.ts, 2, 12))
function f4(s: string, s2?: string) { }
>f4 : Symbol(f4, Decl(unionTypeCallSignatures3.ts, 2, 31))
>s : Symbol(s, Decl(unionTypeCallSignatures3.ts, 3, 12))
>s2 : Symbol(s2, Decl(unionTypeCallSignatures3.ts, 3, 22))
function f5(s?: string, n?: number) { }
>f5 : Symbol(f5, Decl(unionTypeCallSignatures3.ts, 3, 39))
>s : Symbol(s, Decl(unionTypeCallSignatures3.ts, 4, 12))
>n : Symbol(n, Decl(unionTypeCallSignatures3.ts, 4, 23))
function f6(s?: string, ...n: number[]) { }
>f6 : Symbol(f6, Decl(unionTypeCallSignatures3.ts, 4, 39))
>s : Symbol(s, Decl(unionTypeCallSignatures3.ts, 5, 12))
>n : Symbol(n, Decl(unionTypeCallSignatures3.ts, 5, 23))
function f7(s: string, ...sRest: string[]) { }
>f7 : Symbol(f7, Decl(unionTypeCallSignatures3.ts, 5, 43))
>s : Symbol(s, Decl(unionTypeCallSignatures3.ts, 6, 12))
>sRest : Symbol(sRest, Decl(unionTypeCallSignatures3.ts, 6, 22))
var fUnion: typeof f1 | typeof f2 | typeof f3 | typeof f4 | typeof f5 | typeof f6 | typeof f7;
>fUnion : Symbol(fUnion, Decl(unionTypeCallSignatures3.ts, 8, 3))
>f1 : Symbol(f1, Decl(unionTypeCallSignatures3.ts, 0, 0))
>f2 : Symbol(f2, Decl(unionTypeCallSignatures3.ts, 0, 26))
>f3 : Symbol(f3, Decl(unionTypeCallSignatures3.ts, 1, 27))
>f4 : Symbol(f4, Decl(unionTypeCallSignatures3.ts, 2, 31))
>f5 : Symbol(f5, Decl(unionTypeCallSignatures3.ts, 3, 39))
>f6 : Symbol(f6, Decl(unionTypeCallSignatures3.ts, 4, 39))
>f7 : Symbol(f7, Decl(unionTypeCallSignatures3.ts, 5, 43))
fUnion(""); // All constituents can be called by passing a single string.
>fUnion : Symbol(fUnion, Decl(unionTypeCallSignatures3.ts, 8, 3))
@@ -0,0 +1,48 @@
=== tests/cases/conformance/types/union/unionTypeCallSignatures3.ts ===
function f1(s: string) { }
>f1 : (s: string) => void
>s : string
function f2(s?: string) { }
>f2 : (s?: string) => void
>s : string
function f3(...s: string[]) { }
>f3 : (...s: string[]) => void
>s : string[]
function f4(s: string, s2?: string) { }
>f4 : (s: string, s2?: string) => void
>s : string
>s2 : string
function f5(s?: string, n?: number) { }
>f5 : (s?: string, n?: number) => void
>s : string
>n : number
function f6(s?: string, ...n: number[]) { }
>f6 : (s?: string, ...n: number[]) => void
>s : string
>n : number[]
function f7(s: string, ...sRest: string[]) { }
>f7 : (s: string, ...sRest: string[]) => void
>s : string
>sRest : string[]
var fUnion: typeof f1 | typeof f2 | typeof f3 | typeof f4 | typeof f5 | typeof f6 | typeof f7;
>fUnion : ((s: string) => void) | ((s?: string) => void) | ((...s: string[]) => void) | ((s: string, s2?: string) => void) | ((s?: string, n?: number) => void) | ((s?: string, ...n: number[]) => void) | ((s: string, ...sRest: string[]) => void)
>f1 : (s: string) => void
>f2 : (s?: string) => void
>f3 : (...s: string[]) => void
>f4 : (s: string, s2?: string) => void
>f5 : (s?: string, n?: number) => void
>f6 : (s?: string, ...n: number[]) => void
>f7 : (s: string, ...sRest: string[]) => void
fUnion(""); // All constituents can be called by passing a single string.
>fUnion("") : void
>fUnion : ((s: string) => void) | ((s?: string) => void) | ((...s: string[]) => void) | ((s: string, s2?: string) => void) | ((s?: string, n?: number) => void) | ((s?: string, ...n: number[]) => void) | ((s: string, ...sRest: string[]) => void)
>"" : string
@@ -12,29 +12,25 @@ tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(30,1): error
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(31,1): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(36,53): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(37,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(40,12): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(41,12): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(42,12): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(43,12): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(46,12): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(47,12): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(48,12): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(49,12): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(40,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(42,53): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(43,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(47,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(48,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(49,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(55,49): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(56,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(59,12): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(60,12): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(61,12): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(62,12): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(63,12): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(66,12): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(67,12): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(68,12): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(69,12): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(70,12): error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(59,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(61,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(62,49): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(63,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(67,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(68,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(69,12): error TS2346: Supplied parameters do not match any signature of call target.
tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(70,12): error TS2346: Supplied parameters do not match any signature of call target.
==== tests/cases/conformance/types/union/unionTypeConstructSignatures.ts (34 errors) ====
==== tests/cases/conformance/types/union/unionTypeConstructSignatures.ts (30 errors) ====
var numOrDate: number | Date;
var strOrBoolean: string | boolean;
var strOrNum: string | number;
@@ -104,30 +100,26 @@ tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(70,12): erro
var unionWithOptionalParameter2: { new (a: string, b?: number): string; } | { new (a: string, b: number): number };
strOrNum = new unionWithOptionalParameter2('hello'); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
strOrNum = new unionWithOptionalParameter2('hello', 10); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
strOrNum = new unionWithOptionalParameter2('hello', "hello"); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
~~~~~~~
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
strOrNum = new unionWithOptionalParameter2(); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
var unionWithOptionalParameter3: { new (a: string, b?: number): string; } | { new (a: string): number; };
strOrNum = new unionWithOptionalParameter3('hello'); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
strOrNum = new unionWithOptionalParameter3('hello', 10); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
strOrNum = new unionWithOptionalParameter3('hello', "hello"); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
strOrNum = new unionWithOptionalParameter3(); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
var unionWithRestParameter1: { new (a: string, ...b: number[]): string; } | { new (a: string, ...b: number[]): number };
strOrNum = new unionWithRestParameter1('hello');
@@ -143,33 +135,29 @@ tests/cases/conformance/types/union/unionTypeConstructSignatures.ts(70,12): erro
var unionWithRestParameter2: { new (a: string, ...b: number[]): string; } | { new (a: string, b: number): number };
strOrNum = new unionWithRestParameter2('hello'); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
strOrNum = new unionWithRestParameter2('hello', 10); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
strOrNum = new unionWithRestParameter2('hello', 10, 11); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
strOrNum = new unionWithRestParameter2('hello', "hello"); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
~~~~~~~
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
strOrNum = new unionWithRestParameter2(); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
var unionWithRestParameter3: { new (a: string, ...b: number[]): string; } | { new (a: string): number };
strOrNum = new unionWithRestParameter3('hello'); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
strOrNum = new unionWithRestParameter3('hello', 10); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
strOrNum = new unionWithRestParameter3('hello', 10, 11); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
strOrNum = new unionWithRestParameter3('hello', "hello"); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
strOrNum = new unionWithRestParameter3(); // error no call signature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
!!! error TS2346: Supplied parameters do not match any signature of call target.
@@ -25,12 +25,12 @@ unionOfDifferentNumberOfSignatures(); // error - no call signatures
unionOfDifferentNumberOfSignatures(10); // error - no call signatures
unionOfDifferentNumberOfSignatures("hello"); // error - no call signatures
var unionWithDifferentParameterCount: { (a: string): string; } | { (a: string, b: number): number; } ;
var unionWithDifferentParameterCount: { (a: string): string; } | { (a: string, b: number): number; } ;
unionWithDifferentParameterCount();// no call signature
unionWithDifferentParameterCount("hello");// no call signature
unionWithDifferentParameterCount("hello", 10);// no call signature
var unionWithOptionalParameter1: { (a: string, b?: number): string; } | { (a: string, b?: number): number; };
var unionWithOptionalParameter1: { (a: string, b?: number): string; } | { (a: string, b?: number): number; };
strOrNum = unionWithOptionalParameter1('hello');
strOrNum = unionWithOptionalParameter1('hello', 10);
strOrNum = unionWithOptionalParameter1('hello', "hello"); // error in parameter type
@@ -43,7 +43,7 @@ strOrNum = unionWithOptionalParameter2('hello', "hello"); // error no call signa
strOrNum = unionWithOptionalParameter2(); // error no call signature
var unionWithOptionalParameter3: { (a: string, b?: number): string; } | { (a: string): number; };
strOrNum = unionWithOptionalParameter3('hello'); // error no call signature
strOrNum = unionWithOptionalParameter3('hello');
strOrNum = unionWithOptionalParameter3('hello', 10); // error no call signature
strOrNum = unionWithOptionalParameter3('hello', "hello"); // error no call signature
strOrNum = unionWithOptionalParameter3(); // error no call signature
@@ -63,8 +63,9 @@ strOrNum = unionWithRestParameter2('hello', "hello"); // error no call signature
strOrNum = unionWithRestParameter2(); // error no call signature
var unionWithRestParameter3: { (a: string, ...b: number[]): string; } | { (a: string): number };
strOrNum = unionWithRestParameter3('hello'); // error no call signature
strOrNum = unionWithRestParameter3('hello');
strOrNum = unionWithRestParameter3('hello', 10); // error no call signature
strOrNum = unionWithRestParameter3('hello', 10, 11); // error no call signature
strOrNum = unionWithRestParameter3('hello', "hello"); // error no call signature
strOrNum = unionWithRestParameter3(); // error no call signature
strOrNum = unionWithRestParameter3(); // error no call signature
@@ -0,0 +1,35 @@
interface A {
(x: number): number;
(x: string, y?: string): boolean;
(x: Date): void;
<T>(x: T[]): T[];
}
interface B {
(x: number): number;
(x: string): string;
(x: Date): void;
<T>(x: T[]): T[];
}
interface C {
(x: string, ...y: string[]): number;
(x: number, s?: string): number;
<T>(x: T[]): T[];
}
var f1: A | B | C;
var n1 = f1(42); // number
var s1 = f1("abc"); // boolean | string | number
var a1 = f1([true, false]); // boolean[]
var f2: C | B | A;
var n2 = f2(42); // number
var s2 = f2("abc"); // number | string | boolean
var a2 = f2([true, false]); // boolean[]
var f3: B | A | C;
var n3 = f3(42); // number
var s3 = f3("abc"); // string | boolean | number
var a3 = f3([true, false]); // boolean[]
@@ -0,0 +1,11 @@
function f1(s: string) { }
function f2(s?: string) { }
function f3(...s: string[]) { }
function f4(s: string, s2?: string) { }
function f5(s?: string, n?: number) { }
function f6(s?: string, ...n: number[]) { }
function f7(s: string, ...sRest: string[]) { }
var fUnion: typeof f1 | typeof f2 | typeof f3 | typeof f4 | typeof f5 | typeof f6 | typeof f7;
fUnion(""); // All constituents can be called by passing a single string.
@@ -15,6 +15,6 @@
////x.commonProperty./**/
goTo.marker();
verify.memberListContains("toString", "(property) toString: ((radix?: number) => string) | (() => string)");
verify.memberListContains("toString", "(method) toString(): string");
verify.memberListContains("valueOf", "(method) valueOf(): number | string");
verify.memberListCount(2);