Support for/of variables in assertion checking (#37432)

* Support for/of variables in assertion checking

* Integrate with "dotted name" logic

* Add tests
This commit is contained in:
Anders Hejlsberg 2020-03-17 19:20:56 -07:00 committed by GitHub
parent c8e43d878f
commit 0222211acb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 325 additions and 63 deletions

View file

@ -7266,7 +7266,7 @@ namespace ts {
// [Symbol.iterator] or next). This may be because we accessed properties from anyType,
// or it may have led to an error inside getElementTypeOfIterable.
const forOfStatement = declaration.parent.parent;
return checkRightHandSideOfForOf(forOfStatement.expression, forOfStatement.awaitModifier) || anyType;
return checkRightHandSideOfForOf(forOfStatement) || anyType;
}
if (isBindingPattern(declaration.parent)) {
@ -19204,7 +19204,7 @@ namespace ts {
case SyntaxKind.ForInStatement:
return stringType;
case SyntaxKind.ForOfStatement:
return checkRightHandSideOfForOf((<ForOfStatement>parent).expression, (<ForOfStatement>parent).awaitModifier) || errorType;
return checkRightHandSideOfForOf(<ForOfStatement>parent) || errorType;
case SyntaxKind.BinaryExpression:
return getAssignedTypeOfBinaryExpression(<BinaryExpression>parent);
case SyntaxKind.DeleteExpression:
@ -19248,7 +19248,7 @@ namespace ts {
return stringType;
}
if (node.parent.parent.kind === SyntaxKind.ForOfStatement) {
return checkRightHandSideOfForOf(node.parent.parent.expression, node.parent.parent.awaitModifier) || errorType;
return checkRightHandSideOfForOf(node.parent.parent) || errorType;
}
return errorType;
}
@ -19513,11 +19513,10 @@ namespace ts {
return isLengthPushOrUnshift || isElementAssignment;
}
function isDeclarationWithExplicitTypeAnnotation(declaration: Declaration | undefined) {
return !!(declaration && (
declaration.kind === SyntaxKind.VariableDeclaration || declaration.kind === SyntaxKind.Parameter ||
function isDeclarationWithExplicitTypeAnnotation(declaration: Declaration) {
return (declaration.kind === SyntaxKind.VariableDeclaration || declaration.kind === SyntaxKind.Parameter ||
declaration.kind === SyntaxKind.PropertyDeclaration || declaration.kind === SyntaxKind.PropertySignature) &&
getEffectiveTypeAnnotationNode(declaration as VariableDeclaration | ParameterDeclaration | PropertyDeclaration | PropertySignature));
!!getEffectiveTypeAnnotationNode(declaration as VariableDeclaration | ParameterDeclaration | PropertyDeclaration | PropertySignature);
}
function getExplicitTypeOfSymbol(symbol: Symbol, diagnostic?: Diagnostic) {
@ -19525,11 +19524,20 @@ namespace ts {
return getTypeOfSymbol(symbol);
}
if (symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)) {
if (isDeclarationWithExplicitTypeAnnotation(symbol.valueDeclaration)) {
return getTypeOfSymbol(symbol);
}
if (diagnostic && symbol.valueDeclaration) {
addRelatedInfo(diagnostic, createDiagnosticForNode(symbol.valueDeclaration, Diagnostics._0_needs_an_explicit_type_annotation, symbolToString(symbol)));
const declaration = symbol.valueDeclaration;
if (declaration) {
if (isDeclarationWithExplicitTypeAnnotation(declaration)) {
return getTypeOfSymbol(symbol);
}
if (isVariableDeclaration(declaration) && declaration.parent.parent.kind === SyntaxKind.ForOfStatement) {
const expressionType = getTypeOfDottedName(declaration.parent.parent.expression, /*diagnostic*/ undefined);
if (expressionType) {
return getForOfIterationType(declaration.parent.parent, expressionType);
}
}
if (diagnostic) {
addRelatedInfo(diagnostic, createDiagnosticForNode(declaration, Diagnostics._0_needs_an_explicit_type_annotation, symbolToString(symbol)));
}
}
}
}
@ -31585,7 +31593,7 @@ namespace ts {
}
else {
const varExpr = node.initializer;
const iteratedType = checkRightHandSideOfForOf(node.expression, node.awaitModifier);
const iteratedType = checkRightHandSideOfForOf(node);
// There may be a destructuring assignment on the left side
if (varExpr.kind === SyntaxKind.ArrayLiteralExpression || varExpr.kind === SyntaxKind.ObjectLiteralExpression) {
@ -31677,10 +31685,13 @@ namespace ts {
}
}
function checkRightHandSideOfForOf(rhsExpression: Expression, awaitModifier: AwaitKeywordToken | undefined): Type {
const expressionType = checkNonNullExpression(rhsExpression);
const use = awaitModifier ? IterationUse.ForAwaitOf : IterationUse.ForOf;
return checkIteratedTypeOrElementType(use, expressionType, undefinedType, rhsExpression);
function checkRightHandSideOfForOf(statement: ForOfStatement): Type {
return getForOfIterationType(statement, checkNonNullExpression(statement.expression));
}
function getForOfIterationType(statement: ForOfStatement, expressionType: Type) {
const use = statement.awaitModifier ? IterationUse.ForAwaitOf : IterationUse.ForOf;
return checkIteratedTypeOrElementType(use, expressionType, undefinedType, statement.expression);
}
function checkIteratedTypeOrElementType(use: IterationUse, inputType: Type, sentType: Type, errorNode: Node | undefined): Type {
@ -35046,7 +35057,7 @@ namespace ts {
// for ( { a } of elems) {
// }
if (expr.parent.kind === SyntaxKind.ForOfStatement) {
const iteratedType = checkRightHandSideOfForOf((<ForOfStatement>expr.parent).expression, (<ForOfStatement>expr.parent).awaitModifier);
const iteratedType = checkRightHandSideOfForOf(<ForOfStatement>expr.parent);
return checkDestructuringAssignment(expr, iteratedType || errorType);
}
// If this is from "for" initializer

View file

@ -3,16 +3,16 @@ tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(43,9): error TS7
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(87,9): error TS7027: Unreachable code detected.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(122,9): error TS7027: Unreachable code detected.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(137,9): error TS7027: Unreachable code detected.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(143,37): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(144,37): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(145,37): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(148,15): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(149,15): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(150,15): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(151,15): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(156,5): error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(158,5): error TS2776: Assertions require the call target to be an identifier or qualified name.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(160,5): error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(153,37): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(154,37): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(155,37): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(158,15): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(159,15): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(160,15): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(161,15): error TS1228: A type predicate is only allowed in return type position for functions and methods.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(166,5): error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(168,5): error TS2776: Assertions require the call target to be an identifier or qualified name.
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(170,5): error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation.
==== tests/cases/conformance/controlFlow/assertionTypePredicates1.ts (15 errors) ====
@ -166,6 +166,16 @@ tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(160,5): error TS
}
}
function f11(items: Test[]) {
for (let item of items) {
if (item.isTest2()) {
item.z;
}
item.assertIsTest2();
item.z;
}
}
// Invalid constructs
declare let Q1: new (x: unknown) => x is string;
@ -198,7 +208,7 @@ tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(160,5): error TS
assert(typeof x === "string"); // Error
~~~~~~
!!! error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation.
!!! related TS2782 tests/cases/conformance/controlFlow/assertionTypePredicates1.ts:155:11: 'assert' needs an explicit type annotation.
!!! related TS2782 tests/cases/conformance/controlFlow/assertionTypePredicates1.ts:165:11: 'assert' needs an explicit type annotation.
const a = [assert];
a[0](typeof x === "string"); // Error
~~~~
@ -207,8 +217,26 @@ tests/cases/conformance/controlFlow/assertionTypePredicates1.ts(160,5): error TS
t1.assert(typeof x === "string"); // Error
~~~~~~~~~
!!! error TS2775: Assertions require every name in the call target to be declared with an explicit type annotation.
!!! related TS2782 tests/cases/conformance/controlFlow/assertionTypePredicates1.ts:159:11: 't1' needs an explicit type annotation.
!!! related TS2782 tests/cases/conformance/controlFlow/assertionTypePredicates1.ts:169:11: 't1' needs an explicit type annotation.
const t2: Test = new Test();
t2.assert(typeof x === "string");
}
// Repro from #35940
interface Thing {
good: boolean;
isGood(): asserts this is GoodThing;
}
interface GoodThing {
good: true;
}
function example1(things: Thing[]) {
for (let thing of things) {
thing.isGood();
thing.good;
}
}

View file

@ -139,6 +139,16 @@ class Derived extends Test {
}
}
function f11(items: Test[]) {
for (let item of items) {
if (item.isTest2()) {
item.z;
}
item.assertIsTest2();
item.z;
}
}
// Invalid constructs
declare let Q1: new (x: unknown) => x is string;
@ -162,6 +172,24 @@ function f20(x: unknown) {
const t2: Test = new Test();
t2.assert(typeof x === "string");
}
// Repro from #35940
interface Thing {
good: boolean;
isGood(): asserts this is GoodThing;
}
interface GoodThing {
good: true;
}
function example1(things: Thing[]) {
for (let thing of things) {
thing.isGood();
thing.good;
}
}
//// [assertionTypePredicates1.js]
@ -319,6 +347,16 @@ var Derived = /** @class */ (function (_super) {
};
return Derived;
}(Test));
function f11(items) {
for (var _i = 0, items_1 = items; _i < items_1.length; _i++) {
var item = items_1[_i];
if (item.isTest2()) {
item.z;
}
item.assertIsTest2();
item.z;
}
}
function f20(x) {
var assert = function (value) { };
assert(typeof x === "string"); // Error
@ -329,6 +367,13 @@ function f20(x) {
var t2 = new Test();
t2.assert(typeof x === "string");
}
function example1(things) {
for (var _i = 0, things_1 = things; _i < things_1.length; _i++) {
var thing = things_1[_i];
thing.isGood();
thing.good;
}
}
//// [assertionTypePredicates1.d.ts]
@ -362,6 +407,7 @@ declare class Derived extends Test {
foo(x: unknown): void;
baz(x: number): void;
}
declare function f11(items: Test[]): void;
declare let Q1: new (x: unknown) => x is string;
declare let Q2: new (x: boolean) => asserts x;
declare let Q3: new (x: unknown) => asserts x is string;
@ -372,3 +418,11 @@ declare class Wat {
set p2(x: asserts this is string);
}
declare function f20(x: unknown): void;
interface Thing {
good: boolean;
isGood(): asserts this is GoodThing;
}
interface GoodThing {
good: true;
}
declare function example1(things: Thing[]): void;

View file

@ -392,81 +392,153 @@ class Derived extends Test {
}
}
function f11(items: Test[]) {
>f11 : Symbol(f11, Decl(assertionTypePredicates1.ts, 138, 1))
>items : Symbol(items, Decl(assertionTypePredicates1.ts, 140, 13))
>Test : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1))
for (let item of items) {
>item : Symbol(item, Decl(assertionTypePredicates1.ts, 141, 12))
>items : Symbol(items, Decl(assertionTypePredicates1.ts, 140, 13))
if (item.isTest2()) {
>item.isTest2 : Symbol(Test.isTest2, Decl(assertionTypePredicates1.ts, 94, 5))
>item : Symbol(item, Decl(assertionTypePredicates1.ts, 141, 12))
>isTest2 : Symbol(Test.isTest2, Decl(assertionTypePredicates1.ts, 94, 5))
item.z;
>item.z : Symbol(Test2.z, Decl(assertionTypePredicates1.ts, 125, 26))
>item : Symbol(item, Decl(assertionTypePredicates1.ts, 141, 12))
>z : Symbol(Test2.z, Decl(assertionTypePredicates1.ts, 125, 26))
}
item.assertIsTest2();
>item.assertIsTest2 : Symbol(Test.assertIsTest2, Decl(assertionTypePredicates1.ts, 97, 5))
>item : Symbol(item, Decl(assertionTypePredicates1.ts, 141, 12))
>assertIsTest2 : Symbol(Test.assertIsTest2, Decl(assertionTypePredicates1.ts, 97, 5))
item.z;
>item.z : Symbol(Test2.z, Decl(assertionTypePredicates1.ts, 125, 26))
>item : Symbol(item, Decl(assertionTypePredicates1.ts, 141, 12))
>z : Symbol(Test2.z, Decl(assertionTypePredicates1.ts, 125, 26))
}
}
// Invalid constructs
declare let Q1: new (x: unknown) => x is string;
>Q1 : Symbol(Q1, Decl(assertionTypePredicates1.ts, 142, 11))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 142, 21))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 142, 21))
>Q1 : Symbol(Q1, Decl(assertionTypePredicates1.ts, 152, 11))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 152, 21))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 152, 21))
declare let Q2: new (x: boolean) => asserts x;
>Q2 : Symbol(Q2, Decl(assertionTypePredicates1.ts, 143, 11))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 143, 21))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 143, 21))
>Q2 : Symbol(Q2, Decl(assertionTypePredicates1.ts, 153, 11))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 153, 21))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 153, 21))
declare let Q3: new (x: unknown) => asserts x is string;
>Q3 : Symbol(Q3, Decl(assertionTypePredicates1.ts, 144, 11))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 144, 21))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 144, 21))
>Q3 : Symbol(Q3, Decl(assertionTypePredicates1.ts, 154, 11))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 154, 21))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 154, 21))
declare class Wat {
>Wat : Symbol(Wat, Decl(assertionTypePredicates1.ts, 144, 56))
>Wat : Symbol(Wat, Decl(assertionTypePredicates1.ts, 154, 56))
get p1(): this is string;
>p1 : Symbol(Wat.p1, Decl(assertionTypePredicates1.ts, 146, 19), Decl(assertionTypePredicates1.ts, 147, 29))
>p1 : Symbol(Wat.p1, Decl(assertionTypePredicates1.ts, 156, 19), Decl(assertionTypePredicates1.ts, 157, 29))
set p1(x: this is string);
>p1 : Symbol(Wat.p1, Decl(assertionTypePredicates1.ts, 146, 19), Decl(assertionTypePredicates1.ts, 147, 29))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 148, 11))
>p1 : Symbol(Wat.p1, Decl(assertionTypePredicates1.ts, 156, 19), Decl(assertionTypePredicates1.ts, 157, 29))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 158, 11))
get p2(): asserts this is string;
>p2 : Symbol(Wat.p2, Decl(assertionTypePredicates1.ts, 148, 30), Decl(assertionTypePredicates1.ts, 149, 37))
>p2 : Symbol(Wat.p2, Decl(assertionTypePredicates1.ts, 158, 30), Decl(assertionTypePredicates1.ts, 159, 37))
set p2(x: asserts this is string);
>p2 : Symbol(Wat.p2, Decl(assertionTypePredicates1.ts, 148, 30), Decl(assertionTypePredicates1.ts, 149, 37))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 150, 11))
>p2 : Symbol(Wat.p2, Decl(assertionTypePredicates1.ts, 158, 30), Decl(assertionTypePredicates1.ts, 159, 37))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 160, 11))
}
function f20(x: unknown) {
>f20 : Symbol(f20, Decl(assertionTypePredicates1.ts, 151, 1))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 153, 13))
>f20 : Symbol(f20, Decl(assertionTypePredicates1.ts, 161, 1))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 163, 13))
const assert = (value: unknown): asserts value => {}
>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 154, 9))
>value : Symbol(value, Decl(assertionTypePredicates1.ts, 154, 20))
>value : Symbol(value, Decl(assertionTypePredicates1.ts, 154, 20))
>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 164, 9))
>value : Symbol(value, Decl(assertionTypePredicates1.ts, 164, 20))
>value : Symbol(value, Decl(assertionTypePredicates1.ts, 164, 20))
assert(typeof x === "string"); // Error
>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 154, 9))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 153, 13))
>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 164, 9))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 163, 13))
const a = [assert];
>a : Symbol(a, Decl(assertionTypePredicates1.ts, 156, 9))
>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 154, 9))
>a : Symbol(a, Decl(assertionTypePredicates1.ts, 166, 9))
>assert : Symbol(assert, Decl(assertionTypePredicates1.ts, 164, 9))
a[0](typeof x === "string"); // Error
>a : Symbol(a, Decl(assertionTypePredicates1.ts, 156, 9))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 153, 13))
>a : Symbol(a, Decl(assertionTypePredicates1.ts, 166, 9))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 163, 13))
const t1 = new Test();
>t1 : Symbol(t1, Decl(assertionTypePredicates1.ts, 158, 9))
>t1 : Symbol(t1, Decl(assertionTypePredicates1.ts, 168, 9))
>Test : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1))
t1.assert(typeof x === "string"); // Error
>t1.assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12))
>t1 : Symbol(t1, Decl(assertionTypePredicates1.ts, 158, 9))
>t1 : Symbol(t1, Decl(assertionTypePredicates1.ts, 168, 9))
>assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 153, 13))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 163, 13))
const t2: Test = new Test();
>t2 : Symbol(t2, Decl(assertionTypePredicates1.ts, 160, 9))
>t2 : Symbol(t2, Decl(assertionTypePredicates1.ts, 170, 9))
>Test : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1))
>Test : Symbol(Test, Decl(assertionTypePredicates1.ts, 88, 1))
t2.assert(typeof x === "string");
>t2.assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12))
>t2 : Symbol(t2, Decl(assertionTypePredicates1.ts, 160, 9))
>t2 : Symbol(t2, Decl(assertionTypePredicates1.ts, 170, 9))
>assert : Symbol(Test.assert, Decl(assertionTypePredicates1.ts, 90, 12))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 153, 13))
>x : Symbol(x, Decl(assertionTypePredicates1.ts, 163, 13))
}
// Repro from #35940
interface Thing {
>Thing : Symbol(Thing, Decl(assertionTypePredicates1.ts, 172, 1))
good: boolean;
>good : Symbol(Thing.good, Decl(assertionTypePredicates1.ts, 176, 17))
isGood(): asserts this is GoodThing;
>isGood : Symbol(Thing.isGood, Decl(assertionTypePredicates1.ts, 177, 18))
>GoodThing : Symbol(GoodThing, Decl(assertionTypePredicates1.ts, 179, 1))
}
interface GoodThing {
>GoodThing : Symbol(GoodThing, Decl(assertionTypePredicates1.ts, 179, 1))
good: true;
>good : Symbol(GoodThing.good, Decl(assertionTypePredicates1.ts, 181, 21))
}
function example1(things: Thing[]) {
>example1 : Symbol(example1, Decl(assertionTypePredicates1.ts, 183, 1))
>things : Symbol(things, Decl(assertionTypePredicates1.ts, 185, 18))
>Thing : Symbol(Thing, Decl(assertionTypePredicates1.ts, 172, 1))
for (let thing of things) {
>thing : Symbol(thing, Decl(assertionTypePredicates1.ts, 186, 12))
>things : Symbol(things, Decl(assertionTypePredicates1.ts, 185, 18))
thing.isGood();
>thing.isGood : Symbol(Thing.isGood, Decl(assertionTypePredicates1.ts, 177, 18))
>thing : Symbol(thing, Decl(assertionTypePredicates1.ts, 186, 12))
>isGood : Symbol(Thing.isGood, Decl(assertionTypePredicates1.ts, 177, 18))
thing.good;
>thing.good : Symbol(good, Decl(assertionTypePredicates1.ts, 176, 17), Decl(assertionTypePredicates1.ts, 181, 21))
>thing : Symbol(thing, Decl(assertionTypePredicates1.ts, 186, 12))
>good : Symbol(good, Decl(assertionTypePredicates1.ts, 176, 17), Decl(assertionTypePredicates1.ts, 181, 21))
}
}

View file

@ -502,6 +502,38 @@ class Derived extends Test {
}
}
function f11(items: Test[]) {
>f11 : (items: Test[]) => void
>items : Test[]
for (let item of items) {
>item : Test
>items : Test[]
if (item.isTest2()) {
>item.isTest2() : boolean
>item.isTest2 : () => this is Test2
>item : Test
>isTest2 : () => this is Test2
item.z;
>item.z : number
>item : Test2
>z : number
}
item.assertIsTest2();
>item.assertIsTest2() : void
>item.assertIsTest2 : () => asserts this is Test2
>item : Test
>assertIsTest2 : () => asserts this is Test2
item.z;
>item.z : number
>item : Test2
>z : number
}
}
// Invalid constructs
declare let Q1: new (x: unknown) => x is string;
@ -597,3 +629,40 @@ function f20(x: unknown) {
>"string" : "string"
}
// Repro from #35940
interface Thing {
good: boolean;
>good : boolean
isGood(): asserts this is GoodThing;
>isGood : () => asserts this is GoodThing
}
interface GoodThing {
good: true;
>good : true
>true : true
}
function example1(things: Thing[]) {
>example1 : (things: Thing[]) => void
>things : Thing[]
for (let thing of things) {
>thing : Thing
>things : Thing[]
thing.isGood();
>thing.isGood() : void
>thing.isGood : () => asserts this is GoodThing
>thing : Thing
>isGood : () => asserts this is GoodThing
thing.good;
>thing.good : true
>thing : Thing & GoodThing
>good : true
}
}

View file

@ -142,6 +142,16 @@ class Derived extends Test {
}
}
function f11(items: Test[]) {
for (let item of items) {
if (item.isTest2()) {
item.z;
}
item.assertIsTest2();
item.z;
}
}
// Invalid constructs
declare let Q1: new (x: unknown) => x is string;
@ -165,3 +175,21 @@ function f20(x: unknown) {
const t2: Test = new Test();
t2.assert(typeof x === "string");
}
// Repro from #35940
interface Thing {
good: boolean;
isGood(): asserts this is GoodThing;
}
interface GoodThing {
good: true;
}
function example1(things: Thing[]) {
for (let thing of things) {
thing.isGood();
thing.good;
}
}