diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4c1ef08ddd6..e73bbea8fae 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11187,7 +11187,53 @@ namespace ts { return -1; } - function isInLegalParameterTypePredicatePosition(node: Node): boolean { + function checkTypePredicate(node: TypePredicateNode) { + const parent = getTypePredicateParent(node); + if (!parent) { + return; + } + const returnType = getReturnTypeOfSignature(getSignatureFromDeclaration(parent)); + if (!returnType || !(returnType.flags & TypeFlags.PredicateType)) { + return; + } + const { parameterName } = node; + if (parameterName.kind === SyntaxKind.ThisType) { + getTypeFromThisTypeNode(parameterName as ThisTypeNode); + } + else { + const typePredicate = (returnType).predicate; + if (typePredicate.parameterIndex >= 0) { + if (parent.parameters[typePredicate.parameterIndex].dotDotDotToken) { + error(parameterName, + Diagnostics.A_type_predicate_cannot_reference_a_rest_parameter); + } + else { + checkTypeAssignableTo(typePredicate.type, + getTypeOfNode(parent.parameters[typePredicate.parameterIndex]), + node.type); + } + } + else if (parameterName) { + let hasReportedError = false; + for (const { name } of parent.parameters) { + if ((name.kind === SyntaxKind.ObjectBindingPattern || + name.kind === SyntaxKind.ArrayBindingPattern) && + checkIfTypePredicateVariableIsDeclaredInBindingPattern( + name, + parameterName, + typePredicate.parameterName)) { + hasReportedError = true; + break; + } + } + if (!hasReportedError) { + error(node.parameterName, Diagnostics.Cannot_find_parameter_0, typePredicate.parameterName); + } + } + } + } + + function getTypePredicateParent(node: Node): SignatureDeclaration { switch (node.parent.kind) { case SyntaxKind.ArrowFunction: case SyntaxKind.CallSignature: @@ -11196,22 +11242,35 @@ namespace ts { case SyntaxKind.FunctionType: case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: - return node === (node.parent).type; + const parent = node.parent; + if (node === parent.type) { + return parent; + } } - return false; } - function isInLegalThisTypePredicatePosition(node: Node): boolean { - if (isInLegalParameterTypePredicatePosition(node)) { - return true; + function checkIfTypePredicateVariableIsDeclaredInBindingPattern( + pattern: BindingPattern, + predicateVariableNode: Node, + predicateVariableName: string) { + for (const { name } of pattern.elements) { + if (name.kind === SyntaxKind.Identifier && + (name).text === predicateVariableName) { + error(predicateVariableNode, + Diagnostics.A_type_predicate_cannot_reference_element_0_in_a_binding_pattern, + predicateVariableName); + return true; + } + else if (name.kind === SyntaxKind.ArrayBindingPattern || + name.kind === SyntaxKind.ObjectBindingPattern) { + if (checkIfTypePredicateVariableIsDeclaredInBindingPattern( + name, + predicateVariableNode, + predicateVariableName)) { + return true; + } + } } - switch (node.parent.kind) { - case SyntaxKind.PropertyDeclaration: - case SyntaxKind.PropertySignature: - case SyntaxKind.GetAccessor: - return node === (node.parent as (PropertyDeclaration | GetAccessorDeclaration | PropertySignature)).type; - } - return false; } function checkSignatureDeclaration(node: SignatureDeclaration) { @@ -11230,68 +11289,8 @@ namespace ts { forEach(node.parameters, checkParameter); - if (node.type) { - if (node.type.kind === SyntaxKind.TypePredicate) { - const returnType = getReturnTypeOfSignature(getSignatureFromDeclaration(node)); - if (!returnType || !(returnType.flags & TypeFlags.PredicateType)) { - return; - } - const typePredicate = (returnType as PredicateType).predicate; - const typePredicateNode = node.type as TypePredicateNode; - checkSourceElement(typePredicateNode); - if (isIdentifierTypePredicate(typePredicate)) { - if (typePredicate.parameterIndex >= 0) { - if (node.parameters[typePredicate.parameterIndex].dotDotDotToken) { - error(typePredicateNode.parameterName, - Diagnostics.A_type_predicate_cannot_reference_a_rest_parameter); - } - else { - checkTypeAssignableTo(typePredicate.type, - getTypeOfNode(node.parameters[typePredicate.parameterIndex]), - typePredicateNode.type); - } - } - else if (typePredicateNode.parameterName) { - let hasReportedError = false; - for (var param of node.parameters) { - if (hasReportedError) { - break; - } - if (param.name.kind === SyntaxKind.ObjectBindingPattern || - param.name.kind === SyntaxKind.ArrayBindingPattern) { + checkSourceElement(node.type); - (function checkBindingPattern(pattern: BindingPattern) { - for (const element of pattern.elements) { - if (element.name.kind === SyntaxKind.Identifier && - (element.name).text === typePredicate.parameterName) { - - error(typePredicateNode.parameterName, - Diagnostics.A_type_predicate_cannot_reference_element_0_in_a_binding_pattern, - typePredicate.parameterName); - hasReportedError = true; - break; - } - else if (element.name.kind === SyntaxKind.ArrayBindingPattern || - element.name.kind === SyntaxKind.ObjectBindingPattern) { - - checkBindingPattern(element.name); - } - } - })(param.name); - } - } - if (!hasReportedError) { - error(typePredicateNode.parameterName, - Diagnostics.Cannot_find_parameter_0, - typePredicate.parameterName); - } - } - } - } - else { - checkSourceElement(node.type); - } - } if (produceDiagnostics) { checkCollisionWithArgumentsInGeneratedCode(node); @@ -14460,20 +14459,6 @@ namespace ts { } } - function checkTypePredicate(node: TypePredicateNode) { - const { parameterName } = node; - if (parameterName.kind === SyntaxKind.Identifier && !isInLegalParameterTypePredicatePosition(node)) { - error(node, Diagnostics.A_type_predicate_is_only_allowed_in_return_type_position_for_functions_and_methods); - } - else if (parameterName.kind === SyntaxKind.ThisType) { - if (!isInLegalThisTypePredicatePosition(node)) { - error(node, Diagnostics.A_this_based_type_predicate_is_only_allowed_within_a_class_or_interface_s_members_get_accessors_or_return_type_positions_for_functions_and_methods); - } - else { - getTypeFromThisTypeNode(parameterName as ThisTypeNode); - } - } - } function checkSourceElement(node: Node): void { if (!node) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 28b10dd73b4..760da6058c1 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -711,10 +711,6 @@ "category": "Error", "code": 1227 }, - "A type predicate is only allowed in return type position for functions and methods.": { - "category": "Error", - "code": 1228 - }, "A type predicate cannot reference a rest parameter.": { "category": "Error", "code": 1229 @@ -1655,10 +1651,6 @@ "category": "Error", "code": 2518 }, - "A 'this'-based type predicate is only allowed within a class or interface's members, get accessors, or return type positions for functions and methods.": { - "category": "Error", - "code": 2519 - }, "Duplicate identifier '{0}'. Compiler uses declaration '{1}' to support async functions.": { "category": "Error", "code": 2520 diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 390ab210543..420d201adc9 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -896,17 +896,19 @@ namespace ts { return result; } - // Invokes the provided callback then unconditionally restores the parser to the state it - // was in immediately prior to invoking the callback. The result of invoking the callback - // is returned from this function. + /** Invokes the provided callback then unconditionally restores the parser to the state it + * was in immediately prior to invoking the callback. The result of invoking the callback + * is returned from this function. + */ function lookAhead(callback: () => T): T { return speculationHelper(callback, /*isLookAhead*/ true); } - // Invokes the provided callback. If the callback returns something falsy, then it restores - // the parser to the state it was in immediately prior to invoking the callback. If the - // callback returns something truthy, then the parser state is not rolled back. The result - // of invoking the callback is returned from this function. + /** Invokes the provided callback. If the callback returns something falsy, then it restores + * the parser to the state it was in immediately prior to invoking the callback. If the + * callback returns something truthy, then the parser state is not rolled back. The result + * of invoking the callback is returned from this function. + */ function tryParse(callback: () => T): T { return speculationHelper(callback, /*isLookAhead*/ false); } @@ -1948,11 +1950,8 @@ namespace ts { // TYPES - function parseTypeReferenceOrTypePredicate(): TypeReferenceNode | TypePredicateNode { + function parseTypeReference(): TypeReferenceNode { const typeName = parseEntityName(/*allowReservedWords*/ false, Diagnostics.Type_expected); - if (typeName.kind === SyntaxKind.Identifier && token === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) { - return parseTypePredicate(typeName as Identifier); - } const node = createNode(SyntaxKind.TypeReference, typeName.pos); node.typeName = typeName; if (!scanner.hasPrecedingLineBreak() && token === SyntaxKind.LessThanToken) { @@ -2092,10 +2091,10 @@ namespace ts { if (returnTokenRequired) { parseExpected(returnToken); - signature.type = parseType(); + signature.type = parseTypeOrTypePredicate(); } else if (parseOptional(returnToken)) { - signature.type = parseType(); + signature.type = parseTypeOrTypePredicate(); } } @@ -2411,7 +2410,7 @@ namespace ts { case SyntaxKind.SymbolKeyword: // If these are followed by a dot, then parse these out as a dotted type reference instead. const node = tryParse(parseKeywordAndNoDot); - return node || parseTypeReferenceOrTypePredicate(); + return node || parseTypeReference(); case SyntaxKind.StringLiteral: return parseStringLiteralTypeNode(); case SyntaxKind.VoidKeyword: @@ -2434,7 +2433,7 @@ namespace ts { case SyntaxKind.OpenParenToken: return parseParenthesizedType(); default: - return parseTypeReferenceOrTypePredicate(); + return parseTypeReference(); } } @@ -2541,6 +2540,28 @@ namespace ts { return false; } + function parseTypeOrTypePredicate(): TypeNode { + const typePredicateVariable = isIdentifier() && tryParse(parseTypePredicatePrefix); + const type = parseType(); + if (typePredicateVariable) { + const node = createNode(SyntaxKind.TypePredicate, typePredicateVariable.pos); + node.parameterName = typePredicateVariable; + node.type = type; + return finishNode(node); + } + else { + return type; + } + } + + function parseTypePredicatePrefix() { + const id = parseIdentifier(); + if (token === SyntaxKind.IsKeyword && !scanner.hasPrecedingLineBreak()) { + nextToken(); + return id; + } + } + function parseType(): TypeNode { // The rules about 'yield' only apply to actual code/expression contexts. They don't // apply to 'type' contexts. So we disable these parameters here before moving on. diff --git a/tests/baselines/reference/typeAssertions.errors.txt b/tests/baselines/reference/typeAssertions.errors.txt index a2ad28801c8..c7401e4fcf9 100644 --- a/tests/baselines/reference/typeAssertions.errors.txt +++ b/tests/baselines/reference/typeAssertions.errors.txt @@ -7,9 +7,23 @@ tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(37,13): err Property 'q' is missing in type 'SomeDerived'. tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(38,13): error TS2352: Neither type 'SomeBase' nor type 'SomeOther' is assignable to the other. Property 'q' is missing in type 'SomeBase'. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(44,5): error TS2304: Cannot find name 'numOrStr'. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(44,14): error TS1005: '>' expected. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(44,14): error TS2304: Cannot find name 'is'. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(44,17): error TS1005: ')' expected. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(44,17): error TS2304: Cannot find name 'string'. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(44,48): error TS1005: ';' expected. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(45,2): error TS2322: Type 'number | string' is not assignable to type 'string'. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,32): error TS2304: Cannot find name 'numOrStr'. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,41): error TS1005: ')' expected. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,41): error TS2304: Cannot find name 'is'. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,44): error TS1005: ';' expected. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,44): error TS2304: Cannot find name 'string'. +tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(48,50): error TS1005: ';' expected. -==== tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts (5 errors) ==== +==== tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts (18 errors) ==== // Function call whose argument is a 1 arg generic function call with explicit type arguments function fn1(t: T) { } function fn2(t: any) { } @@ -64,5 +78,41 @@ tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts(38,13): err !!! error TS2352: Property 'q' is missing in type 'SomeBase'. someOther = someOther; + // Type assertion cannot be a type-predicate type + var numOrStr: number | string; + var str: string; + if((numOrStr === undefined)) { // Error + ~~~~~~~~ +!!! error TS2304: Cannot find name 'numOrStr'. + ~~ +!!! error TS1005: '>' expected. + ~~ +!!! error TS2304: Cannot find name 'is'. + ~~~~~~ +!!! error TS1005: ')' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'string'. + ~ +!!! error TS1005: ';' expected. + str = numOrStr; // Error, no narrowing occurred + ~~~ +!!! error TS2322: Type 'number | string' is not assignable to type 'string'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + } + + if((numOrStr === undefined) as numOrStr is string) { // Error + ~~~~~~~~ +!!! error TS2304: Cannot find name 'numOrStr'. + ~~ +!!! error TS1005: ')' expected. + ~~ +!!! error TS2304: Cannot find name 'is'. + ~~~~~~ +!!! error TS1005: ';' expected. + ~~~~~~ +!!! error TS2304: Cannot find name 'string'. + ~ +!!! error TS1005: ';' expected. + } \ No newline at end of file diff --git a/tests/baselines/reference/typeAssertions.js b/tests/baselines/reference/typeAssertions.js index b58a46c37f6..1d33fa927a7 100644 --- a/tests/baselines/reference/typeAssertions.js +++ b/tests/baselines/reference/typeAssertions.js @@ -39,6 +39,15 @@ someOther = someDerived; // Error someOther = someBase; // Error someOther = someOther; +// Type assertion cannot be a type-predicate type +var numOrStr: number | string; +var str: string; +if((numOrStr === undefined)) { // Error + str = numOrStr; // Error, no narrowing occurred +} + +if((numOrStr === undefined) as numOrStr is string) { // Error +} @@ -87,3 +96,16 @@ someDerived = someOther; // Error someOther = someDerived; // Error someOther = someBase; // Error someOther = someOther; +// Type assertion cannot be a type-predicate type +var numOrStr; +var str; +if (is) + string > (numOrStr === undefined); +{ + str = numOrStr; // Error, no narrowing occurred +} +if ((numOrStr === undefined)) + is; +string; +{ +} diff --git a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt index e1fdf303870..4756b83b300 100644 --- a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt +++ b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt @@ -1,15 +1,21 @@ +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(2,7): error TS2300: Duplicate identifier 'A'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(15,12): error TS2322: Type 'string' is not assignable to type 'x is A'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,55): error TS2304: Cannot find name 'x'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,57): error TS1144: '{' or ';' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,57): error TS2304: Cannot find name 'is'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,60): error TS1005: ';' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(18,62): error TS1005: ';' expected. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(22,33): error TS2304: Cannot find name 'x'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(26,33): error TS1225: Cannot find parameter 'x'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(30,10): error TS2391: Function implementation is missing or not immediately following the declaration. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(31,5): error TS1131: Property or signature expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(31,5): error TS7027: Unreachable code detected. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(32,1): error TS1128: Declaration or statement expected. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(34,38): error TS1225: Cannot find parameter 'x'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(38,51): error TS2322: Type 'B' is not assignable to type 'A'. Property 'propA' is missing in type 'B'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(42,56): error TS2322: Type 'number' is not assignable to type 'string'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(46,56): error TS2322: Type 'T[]' is not assignable to type 'string'. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(50,1): error TS7027: Unreachable code detected. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(60,7): error TS2339: Property 'propB' does not exist on type 'A'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(65,7): error TS2339: Property 'propB' does not exist on type 'A'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(70,7): error TS2339: Property 'propB' does not exist on type 'A'. @@ -23,27 +29,40 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(85,1): Type predicate 'p2 is A' is not assignable to 'p1 is A'. Parameter 'p2' is not in the same position as parameter 'p1'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(91,1): error TS2322: Type '(p1: any, p2: any, p3: any) => p1 is A' is not assignable to type '(p1: any, p2: any) => p1 is A'. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,9): error TS1228: A type predicate is only allowed in return type position for functions and methods. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,16): error TS1228: A type predicate is only allowed in return type position for functions and methods. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,20): error TS1228: A type predicate is only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,9): error TS2304: Cannot find name 'b'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,11): error TS1005: '=' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,11): error TS2304: Cannot find name 'is'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,14): error TS1005: ',' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,14): error TS2300: Duplicate identifier 'A'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,16): error TS2304: Cannot find name 'b'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,18): error TS1005: '=' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,18): error TS2304: Cannot find name 'is'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,21): error TS1005: ',' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,20): error TS2304: Cannot find name 'b'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,22): error TS1144: '{' or ';' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,22): error TS2304: Cannot find name 'is'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,25): error TS1005: ';' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,27): error TS1005: ';' expected. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(105,16): error TS2322: Type 'boolean' is not assignable to type 'D'. Property 'm1' is missing in type 'Boolean'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(105,16): error TS2409: Return type of constructor signature must be assignable to the instance type of the class -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(107,20): error TS1228: A type predicate is only allowed in return type position for functions and methods. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(110,20): error TS1228: A type predicate is only allowed in return type position for functions and methods. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(111,16): error TS2408: Setters cannot return a value. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(116,18): error TS1228: A type predicate is only allowed in return type position for functions and methods. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(120,22): error TS1225: Cannot find parameter 'p1'. -tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(120,22): error TS1228: A type predicate is only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(120,22): error TS2304: Cannot find name 'p1'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(120,25): error TS1005: ';' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(120,25): error TS2304: Cannot find name 'is'. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(120,28): error TS1005: ';' expected. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(121,1): error TS1128: Declaration or statement expected. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(124,20): error TS1229: A type predicate cannot reference a rest parameter. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(129,34): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(133,34): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern. -==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (33 errors) ==== +==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (50 errors) ==== class A { + ~ +!!! error TS2300: Duplicate identifier 'A'. propA: number; } @@ -62,6 +81,16 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39 } function hasTypeGuardTypeInsideTypeGuardType(x): x is x is A { + ~ +!!! error TS2304: Cannot find name 'x'. + ~~ +!!! error TS1144: '{' or ';' expected. + ~~ +!!! error TS2304: Cannot find name 'is'. + ~ +!!! error TS1005: ';' expected. + ~ +!!! error TS1005: ';' expected. return true; } @@ -83,6 +112,8 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39 return true; ~~~~~~ !!! error TS1131: Property or signature expected. + ~~~~~~ +!!! error TS7027: Unreachable code detected. } ~ !!! error TS1128: Declaration or statement expected. @@ -113,8 +144,6 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39 } let a: A; - ~~~ -!!! error TS7027: Unreachable code detected. let b: B; declare function isB(p1): p1 is B; @@ -181,14 +210,36 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39 // Type predicates in non-return type positions var b1: b is A; - ~~~~~~ -!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. + ~ +!!! error TS2304: Cannot find name 'b'. + ~~ +!!! error TS1005: '=' expected. + ~~ +!!! error TS2304: Cannot find name 'is'. + ~ +!!! error TS1005: ',' expected. + ~ +!!! error TS2300: Duplicate identifier 'A'. function b2(a: b is A) {}; - ~~~~~~ -!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. + ~ +!!! error TS2304: Cannot find name 'b'. + ~~ +!!! error TS1005: '=' expected. + ~~ +!!! error TS2304: Cannot find name 'is'. + ~ +!!! error TS1005: ',' expected. function b3(): A | b is A { - ~~~~~~ -!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. + ~ +!!! error TS2304: Cannot find name 'b'. + ~~ +!!! error TS1144: '{' or ';' expected. + ~~ +!!! error TS2304: Cannot find name 'is'. + ~ +!!! error TS1005: ';' expected. + ~ +!!! error TS1005: ';' expected. return true; }; @@ -203,13 +254,9 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39 !!! error TS2409: Return type of constructor signature must be assignable to the instance type of the class } get m1(p1: A): p1 is C { - ~~~~~~~ -!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. return true; } set m2(p1: A): p1 is C { - ~~~~~~~ -!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. return true; ~~~~ !!! error TS2408: Setters cannot return a value. @@ -218,17 +265,21 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39 interface I1 { new (p1: A): p1 is C; - ~~~~~~~ -!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. } interface I2 { [index: number]: p1 is C; ~~ -!!! error TS1225: Cannot find parameter 'p1'. - ~~~~~~~ -!!! error TS1228: A type predicate is only allowed in return type position for functions and methods. +!!! error TS2304: Cannot find name 'p1'. + ~~ +!!! error TS1005: ';' expected. + ~~ +!!! error TS2304: Cannot find name 'is'. + ~ +!!! error TS1005: ';' expected. } + ~ +!!! error TS1128: Declaration or statement expected. // Reference to rest parameter function b4(...a): a is A { diff --git a/tests/baselines/reference/typeGuardFunctionErrors.js b/tests/baselines/reference/typeGuardFunctionErrors.js index 5e69749e582..dcd8ffcb265 100644 --- a/tests/baselines/reference/typeGuardFunctionErrors.js +++ b/tests/baselines/reference/typeGuardFunctionErrors.js @@ -171,7 +171,9 @@ var C = (function (_super) { function hasANonBooleanReturnStatement(x) { return ''; } -function hasTypeGuardTypeInsideTypeGuardType(x) { +is; +A; +{ return true; } function hasMissingIsKeyword() { @@ -224,10 +226,14 @@ assign3 = function (p1, p2, p3) { return true; }; // Type predicates in non-return type positions -var b1; -function b2(a) { } +var b1 = is, A; +function b2(a, A) { + if (a === void 0) { a = is; } +} ; -function b3() { +is; +A; +{ return true; } ; @@ -252,6 +258,8 @@ var D = (function () { }); return D; }()); +is; +C; // Reference to rest parameter function b4() { var a = []; diff --git a/tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts b/tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts index 2acbbe53789..f30eafb3918 100644 --- a/tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts +++ b/tests/cases/conformance/expressions/typeAssertions/typeAssertions.ts @@ -38,4 +38,13 @@ someOther = someDerived; // Error someOther = someBase; // Error someOther = someOther; +// Type assertion cannot be a type-predicate type +var numOrStr: number | string; +var str: string; +if((numOrStr === undefined)) { // Error + str = numOrStr; // Error, no narrowing occurred +} + +if((numOrStr === undefined) as numOrStr is string) { // Error +}