diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9babfdec339..2be010d35f7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -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 = (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; } diff --git a/tests/baselines/reference/contextualTypeWithUnionTypeCallSignatures.symbols b/tests/baselines/reference/contextualTypeWithUnionTypeCallSignatures.symbols index 172336603ab..3e23a7812f5 100644 --- a/tests/baselines/reference/contextualTypeWithUnionTypeCallSignatures.symbols +++ b/tests/baselines/reference/contextualTypeWithUnionTypeCallSignatures.symbols @@ -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)) diff --git a/tests/baselines/reference/contextualTypeWithUnionTypeCallSignatures.types b/tests/baselines/reference/contextualTypeWithUnionTypeCallSignatures.types index 02dfecf5c08..8e1915d4754 100644 --- a/tests/baselines/reference/contextualTypeWithUnionTypeCallSignatures.types +++ b/tests/baselines/reference/contextualTypeWithUnionTypeCallSignatures.types @@ -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 diff --git a/tests/baselines/reference/mismatchedExplicitTypeParameterAndArgumentType.errors.txt b/tests/baselines/reference/mismatchedExplicitTypeParameterAndArgumentType.errors.txt index 7445ab85a54..e8649cfb567 100644 --- a/tests/baselines/reference/mismatchedExplicitTypeParameterAndArgumentType.errors.txt +++ b/tests/baselines/reference/mismatchedExplicitTypeParameterAndArgumentType.errors.txt @@ -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(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([1, ""], (x) => x.toString()); var r6 = map([1, ""], (x) => x.toString()); var r7 = map([1, ""], (x) => x.toString()); // error diff --git a/tests/baselines/reference/typeGuardsInConditionalExpression.errors.txt b/tests/baselines/reference/typeGuardsInConditionalExpression.errors.txt deleted file mode 100644 index 37a662e007c..00000000000 --- a/tests/baselines/reference/typeGuardsInConditionalExpression.errors.txt +++ /dev/null @@ -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 - } \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardsInConditionalExpression.symbols b/tests/baselines/reference/typeGuardsInConditionalExpression.symbols new file mode 100644 index 00000000000..ac35c1f18b9 --- /dev/null +++ b/tests/baselines/reference/typeGuardsInConditionalExpression.symbols @@ -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)) +} diff --git a/tests/baselines/reference/typeGuardsInConditionalExpression.types b/tests/baselines/reference/typeGuardsInConditionalExpression.types new file mode 100644 index 00000000000..ef048fb8562 --- /dev/null +++ b/tests/baselines/reference/typeGuardsInConditionalExpression.types @@ -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 +} diff --git a/tests/baselines/reference/typeGuardsInIfStatement.errors.txt b/tests/baselines/reference/typeGuardsInIfStatement.errors.txt deleted file mode 100644 index e675daffd6e..00000000000 --- a/tests/baselines/reference/typeGuardsInIfStatement.errors.txt +++ /dev/null @@ -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 - } - } \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardsInIfStatement.symbols b/tests/baselines/reference/typeGuardsInIfStatement.symbols new file mode 100644 index 00000000000..d940e10e066 --- /dev/null +++ b/tests/baselines/reference/typeGuardsInIfStatement.symbols @@ -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)) + } +} diff --git a/tests/baselines/reference/typeGuardsInIfStatement.types b/tests/baselines/reference/typeGuardsInIfStatement.types new file mode 100644 index 00000000000..e049d318a02 --- /dev/null +++ b/tests/baselines/reference/typeGuardsInIfStatement.types @@ -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 + } +} diff --git a/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.errors.txt b/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.errors.txt deleted file mode 100644 index f44e433a2c8..00000000000 --- a/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.errors.txt +++ /dev/null @@ -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 - } \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.symbols b/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.symbols new file mode 100644 index 00000000000..59f51d21e71 --- /dev/null +++ b/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.symbols @@ -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)) +} diff --git a/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.types b/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.types new file mode 100644 index 00000000000..b69c80ff55a --- /dev/null +++ b/tests/baselines/reference/typeGuardsInRightOperandOfAndAndOperator.types @@ -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 +} diff --git a/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.errors.txt b/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.errors.txt deleted file mode 100644 index f34d035fa40..00000000000 --- a/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.errors.txt +++ /dev/null @@ -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 - } \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.symbols b/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.symbols new file mode 100644 index 00000000000..d33f0b6877b --- /dev/null +++ b/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.symbols @@ -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)) +} diff --git a/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.types b/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.types new file mode 100644 index 00000000000..b2f5401e843 --- /dev/null +++ b/tests/baselines/reference/typeGuardsInRightOperandOfOrOrOperator.types @@ -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 +} diff --git a/tests/baselines/reference/unionTypeCallSignatures.errors.txt b/tests/baselines/reference/unionTypeCallSignatures.errors.txt index c25a2bf9f84..ebe38a589ee 100644 --- a/tests/baselines/reference/unionTypeCallSignatures.errors.txt +++ b/tests/baselines/reference/unionTypeCallSignatures.errors.txt @@ -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. \ No newline at end of file +!!! error TS2346: Supplied parameters do not match any signature of call target. + + \ No newline at end of file diff --git a/tests/baselines/reference/unionTypeCallSignatures.js b/tests/baselines/reference/unionTypeCallSignatures.js index a4000038ce6..fc3dfc8ebbc 100644 --- a/tests/baselines/reference/unionTypeCallSignatures.js +++ b/tests/baselines/reference/unionTypeCallSignatures.js @@ -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 diff --git a/tests/baselines/reference/unionTypeCallSignatures2.js b/tests/baselines/reference/unionTypeCallSignatures2.js new file mode 100644 index 00000000000..7ec5180972a --- /dev/null +++ b/tests/baselines/reference/unionTypeCallSignatures2.js @@ -0,0 +1,51 @@ +//// [unionTypeCallSignatures2.ts] +interface A { + (x: number): number; + (x: string, y?: string): boolean; + (x: Date): void; + (x: T[]): T[]; +} + +interface B { + (x: number): number; + (x: string): string; + (x: Date): void; + (x: T[]): T[]; +} + +interface C { + (x: string, ...y: string[]): number; + (x: number, s?: string): number; + (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[] diff --git a/tests/baselines/reference/unionTypeCallSignatures2.symbols b/tests/baselines/reference/unionTypeCallSignatures2.symbols new file mode 100644 index 00000000000..35ba9464df0 --- /dev/null +++ b/tests/baselines/reference/unionTypeCallSignatures2.symbols @@ -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)) + + (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)) + + (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)) + + (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)) + + diff --git a/tests/baselines/reference/unionTypeCallSignatures2.types b/tests/baselines/reference/unionTypeCallSignatures2.types new file mode 100644 index 00000000000..64295c1b452 --- /dev/null +++ b/tests/baselines/reference/unionTypeCallSignatures2.types @@ -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 + + (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 + + (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 + + (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 + + diff --git a/tests/baselines/reference/unionTypeCallSignatures3.js b/tests/baselines/reference/unionTypeCallSignatures3.js new file mode 100644 index 00000000000..2dae152e474 --- /dev/null +++ b/tests/baselines/reference/unionTypeCallSignatures3.js @@ -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. diff --git a/tests/baselines/reference/unionTypeCallSignatures3.symbols b/tests/baselines/reference/unionTypeCallSignatures3.symbols new file mode 100644 index 00000000000..45dffe2d821 --- /dev/null +++ b/tests/baselines/reference/unionTypeCallSignatures3.symbols @@ -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)) + diff --git a/tests/baselines/reference/unionTypeCallSignatures3.types b/tests/baselines/reference/unionTypeCallSignatures3.types new file mode 100644 index 00000000000..52aae993e4a --- /dev/null +++ b/tests/baselines/reference/unionTypeCallSignatures3.types @@ -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 + diff --git a/tests/baselines/reference/unionTypeConstructSignatures.errors.txt b/tests/baselines/reference/unionTypeConstructSignatures.errors.txt index cbdcc9ed12a..0332aa61110 100644 --- a/tests/baselines/reference/unionTypeConstructSignatures.errors.txt +++ b/tests/baselines/reference/unionTypeConstructSignatures.errors.txt @@ -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. \ No newline at end of file +!!! error TS2346: Supplied parameters do not match any signature of call target. \ No newline at end of file diff --git a/tests/cases/conformance/types/union/unionTypeCallSignatures.ts b/tests/cases/conformance/types/union/unionTypeCallSignatures.ts index 1261de3299e..ca599329743 100644 --- a/tests/cases/conformance/types/union/unionTypeCallSignatures.ts +++ b/tests/cases/conformance/types/union/unionTypeCallSignatures.ts @@ -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 \ No newline at end of file +strOrNum = unionWithRestParameter3(); // error no call signature + diff --git a/tests/cases/conformance/types/union/unionTypeCallSignatures2.ts b/tests/cases/conformance/types/union/unionTypeCallSignatures2.ts new file mode 100644 index 00000000000..2fa5190cc35 --- /dev/null +++ b/tests/cases/conformance/types/union/unionTypeCallSignatures2.ts @@ -0,0 +1,35 @@ +interface A { + (x: number): number; + (x: string, y?: string): boolean; + (x: Date): void; + (x: T[]): T[]; +} + +interface B { + (x: number): number; + (x: string): string; + (x: Date): void; + (x: T[]): T[]; +} + +interface C { + (x: string, ...y: string[]): number; + (x: number, s?: string): number; + (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[] + diff --git a/tests/cases/conformance/types/union/unionTypeCallSignatures3.ts b/tests/cases/conformance/types/union/unionTypeCallSignatures3.ts new file mode 100644 index 00000000000..8549315a319 --- /dev/null +++ b/tests/cases/conformance/types/union/unionTypeCallSignatures3.ts @@ -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. diff --git a/tests/cases/fourslash/completionEntryForUnionProperty2.ts b/tests/cases/fourslash/completionEntryForUnionProperty2.ts index 0b2d50fc130..aa5bc40b5e3 100644 --- a/tests/cases/fourslash/completionEntryForUnionProperty2.ts +++ b/tests/cases/fourslash/completionEntryForUnionProperty2.ts @@ -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); \ No newline at end of file