Skip to content

Commit 07cf82a

Browse files
committed
Make type guard function types invariant in the type guarded for.
- Fix one break in the compiler. - Type guards like `isNetworked(): this is (Networked & this)` have been obsolete in favor of `isNetworked(): this is Networked` ever since narrowing was enhanced to take an intersection in a370908, and the first form now causes a problem: a subclass fails to be a subtype of its superclass because `this` appears in a non-covariant position. So replace all occurrences of the first form with the second form in the test suite. Fixes #26981.
1 parent bbf559b commit 07cf82a

19 files changed

+274
-223
lines changed

src/compiler/checker.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -11722,7 +11722,10 @@ namespace ts {
1172211722
}
1172311723
}
1172411724

11725-
const related = compareTypes(source.type, target.type, reportErrors);
11725+
let related = compareTypes(source.type, target.type, reportErrors);
11726+
if (related) {
11727+
related &= compareTypes(target.type, source.type, reportErrors);
11728+
}
1172611729
if (related === Ternary.False && reportErrors) {
1172711730
errorReporter!(Diagnostics.Type_predicate_0_is_not_assignable_to_1, typePredicateToString(source), typePredicateToString(target));
1172811731
}

src/services/documentHighlights.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ namespace ts.DocumentHighlights {
7575
case SyntaxKind.SetKeyword:
7676
return getFromAllDeclarations(isAccessor, [SyntaxKind.GetKeyword, SyntaxKind.SetKeyword]);
7777
case SyntaxKind.AwaitKeyword:
78-
return useParent(node.parent, isAwaitExpression, getAsyncAndAwaitOccurrences);
78+
return useParent<AwaitExpression>(node.parent, isAwaitExpression, getAsyncAndAwaitOccurrences);
7979
case SyntaxKind.AsyncKeyword:
8080
return highlightSpans(getAsyncAndAwaitOccurrences(node));
8181
case SyntaxKind.YieldKeyword:

tests/baselines/reference/typeGuardFunctionErrors.errors.txt

+58-48
Original file line numberDiff line numberDiff line change
@@ -16,59 +16,62 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(41,56)
1616
Type 'number' is not assignable to type 'string'.
1717
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(45,56): error TS2677: A type predicate's type must be assignable to its parameter's type.
1818
Type 'T[]' is not assignable to type 'string'.
19-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(59,7): error TS2551: Property 'propB' does not exist on type 'A'. Did you mean 'propA'?
20-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(64,7): error TS2551: Property 'propB' does not exist on type 'A'. Did you mean 'propA'?
21-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(69,7): error TS2551: Property 'propB' does not exist on type 'A'. Did you mean 'propA'?
22-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(74,46): error TS2345: Argument of type '(p1: any) => p1 is C' is not assignable to parameter of type '(p1: any) => p1 is B'.
23-
Type predicate 'p1 is C' is not assignable to 'p1 is B'.
24-
Property 'propB' is missing in type 'C' but required in type 'B'.
25-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(78,1): error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => p1 is A'.
19+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(60,7): error TS2551: Property 'propB' does not exist on type 'A'. Did you mean 'propA'?
20+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(65,7): error TS2551: Property 'propB' does not exist on type 'A'. Did you mean 'propA'?
21+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(70,7): error TS2551: Property 'propB' does not exist on type 'A'. Did you mean 'propA'?
22+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(75,46): error TS2345: Argument of type '(p1: any) => p1 is C' is not assignable to parameter of type '(p1: any) => p1 is A'.
23+
Type predicate 'p1 is C' is not assignable to 'p1 is A'.
24+
Property 'propC' is missing in type 'A' but required in type 'C'.
25+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(77,47): error TS2345: Argument of type '(p1: any) => p1 is A' is not assignable to parameter of type '(p1: any) => p1 is C'.
26+
Type predicate 'p1 is A' is not assignable to 'p1 is C'.
27+
Type 'A' is not assignable to type 'C'.
28+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(81,1): error TS2322: Type '(p1: any, p2: any) => boolean' is not assignable to type '(p1: any, p2: any) => p1 is A'.
2629
Signature '(p1: any, p2: any): boolean' must be a type predicate.
27-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(84,1): error TS2322: Type '(p1: any, p2: any) => p2 is A' is not assignable to type '(p1: any, p2: any) => p1 is A'.
30+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(87,1): error TS2322: Type '(p1: any, p2: any) => p2 is A' is not assignable to type '(p1: any, p2: any) => p1 is A'.
2831
Type predicate 'p2 is A' is not assignable to 'p1 is A'.
2932
Parameter 'p2' is not in the same position as parameter 'p1'.
30-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(90,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'.
31-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(95,9): error TS2304: Cannot find name 'b'.
32-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(95,11): error TS1005: ',' expected.
33-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(95,14): error TS1005: ',' expected.
34-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(95,14): error TS2300: Duplicate identifier 'A'.
35-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,16): error TS2304: Cannot find name 'b'.
36-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,18): error TS1005: ',' expected.
37-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,21): error TS1005: ',' expected.
38-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,20): error TS2304: Cannot find name 'b'.
39-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,22): error TS1144: '{' or ';' expected.
40-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,25): error TS1005: ';' expected.
41-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,27): error TS1005: ';' expected.
42-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(103,25): error TS1228: A type predicate is only allowed in return type position for functions and methods.
43-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(104,9): error TS2322: Type 'true' is not assignable to type 'D'.
44-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(104,9): error TS2409: Return type of constructor signature must be assignable to the instance type of the class.
45-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(106,20): error TS1228: A type predicate is only allowed in return type position for functions and methods.
33+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(93,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'.
34+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,9): error TS2304: Cannot find name 'b'.
35+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,11): error TS1005: ',' expected.
36+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,14): error TS1005: ',' expected.
37+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,14): error TS2300: Duplicate identifier 'A'.
38+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(99,16): error TS2304: Cannot find name 'b'.
39+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(99,18): error TS1005: ',' expected.
40+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(99,21): error TS1005: ',' expected.
41+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(100,20): error TS2304: Cannot find name 'b'.
42+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(100,22): error TS1144: '{' or ';' expected.
43+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(100,25): error TS1005: ';' expected.
44+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(100,27): error TS1005: ';' expected.
45+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(106,25): error TS1228: A type predicate is only allowed in return type position for functions and methods.
46+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(107,9): error TS2322: Type 'true' is not assignable to type 'D'.
47+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(107,9): error TS2409: Return type of constructor signature must be assignable to the instance type of the class.
4648
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(109,20): error TS1228: A type predicate is only allowed in return type position for functions and methods.
47-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(110,9): error TS2408: Setters cannot return a value.
48-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(115,18): error TS1228: A type predicate is only allowed in return type position for functions and methods.
49-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(119,22): error TS2304: Cannot find name 'p1'.
50-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(119,25): error TS1005: ';' expected.
51-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(119,28): error TS1005: ';' expected.
52-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(120,1): error TS1128: Declaration or statement expected.
53-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(123,20): error TS1229: A type predicate cannot reference a rest parameter.
54-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(128,34): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern.
55-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(132,34): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern.
56-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(136,39): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern.
57-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(152,68): error TS2344: Type 'T | "d"' does not satisfy the constraint 'Keys'.
49+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(112,20): error TS1228: A type predicate is only allowed in return type position for functions and methods.
50+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(113,9): error TS2408: Setters cannot return a value.
51+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(118,18): error TS1228: A type predicate is only allowed in return type position for functions and methods.
52+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(122,22): error TS2304: Cannot find name 'p1'.
53+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(122,25): error TS1005: ';' expected.
54+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(122,28): error TS1005: ';' expected.
55+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(123,1): error TS1128: Declaration or statement expected.
56+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(126,20): error TS1229: A type predicate cannot reference a rest parameter.
57+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(131,34): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern.
58+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(135,34): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern.
59+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(139,39): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern.
60+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(155,68): error TS2344: Type 'T | "d"' does not satisfy the constraint 'Keys'.
5861
Type '"d"' is not assignable to type 'Keys'.
59-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(159,31): error TS2344: Type 'Bar' does not satisfy the constraint 'Foo'.
62+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(162,31): error TS2344: Type 'Bar' does not satisfy the constraint 'Foo'.
6063
Types of property ''a'' are incompatible.
6164
Type 'number' is not assignable to type 'string'.
62-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(162,31): error TS2344: Type 'Bar' does not satisfy the constraint 'Foo'.
63-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(163,35): error TS2344: Type 'number' does not satisfy the constraint 'Foo'.
64-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(164,51): error TS2344: Type 'Bar' does not satisfy the constraint 'Foo'.
65-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(165,51): error TS2344: Type 'number' does not satisfy the constraint 'Foo'.
66-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(166,45): error TS2677: A type predicate's type must be assignable to its parameter's type.
65+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(165,31): error TS2344: Type 'Bar' does not satisfy the constraint 'Foo'.
66+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(166,35): error TS2344: Type 'number' does not satisfy the constraint 'Foo'.
67+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(167,51): error TS2344: Type 'Bar' does not satisfy the constraint 'Foo'.
68+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(168,51): error TS2344: Type 'number' does not satisfy the constraint 'Foo'.
69+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(169,45): error TS2677: A type predicate's type must be assignable to its parameter's type.
6770
Type 'NeedsFoo<number>' is not assignable to type 'number'.
68-
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(166,54): error TS2344: Type 'number' does not satisfy the constraint 'Foo'.
71+
tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(169,54): error TS2344: Type 'number' does not satisfy the constraint 'Foo'.
6972

7073

71-
==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (56 errors) ====
74+
==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (57 errors) ====
7275
class A {
7376
~
7477
!!! error TS2300: Duplicate identifier 'A'.
@@ -154,6 +157,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(166,54
154157
let a: A;
155158
let b: B;
156159

160+
declare function isA(p1): p1 is A;
157161
declare function isB(p1): p1 is B;
158162
declare function isC(p1): p1 is C;
159163
declare function funA(p1: any, p2: any): p1 is B;
@@ -184,13 +188,19 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(166,54
184188
}
185189

186190
// Type predicate type is not assignable
187-
declare function acceptingDifferentSignatureTypeGuardFunction(p1: (p1) => p1 is B);
191+
declare function acceptingDifferentSignatureTypeGuardFunction(p1: (p1) => p1 is A);
188192
acceptingDifferentSignatureTypeGuardFunction(isC);
189193
~~~
190-
!!! error TS2345: Argument of type '(p1: any) => p1 is C' is not assignable to parameter of type '(p1: any) => p1 is B'.
191-
!!! error TS2345: Type predicate 'p1 is C' is not assignable to 'p1 is B'.
192-
!!! error TS2345: Property 'propB' is missing in type 'C' but required in type 'B'.
193-
!!! related TS2728 tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts:6:5: 'propB' is declared here.
194+
!!! error TS2345: Argument of type '(p1: any) => p1 is C' is not assignable to parameter of type '(p1: any) => p1 is A'.
195+
!!! error TS2345: Type predicate 'p1 is C' is not assignable to 'p1 is A'.
196+
!!! error TS2345: Property 'propC' is missing in type 'A' but required in type 'C'.
197+
!!! related TS2728 tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts:10:5: 'propC' is declared here.
198+
declare function acceptingDifferentSignatureTypeGuardFunction2(p1: (p1) => p1 is C);
199+
acceptingDifferentSignatureTypeGuardFunction2(isA);
200+
~~~
201+
!!! error TS2345: Argument of type '(p1: any) => p1 is A' is not assignable to parameter of type '(p1: any) => p1 is C'.
202+
!!! error TS2345: Type predicate 'p1 is A' is not assignable to 'p1 is C'.
203+
!!! error TS2345: Type 'A' is not assignable to type 'C'.
194204

195205
// Boolean not assignable to type guard
196206
var assign1: (p1, p2) => p1 is A;

tests/baselines/reference/typeGuardFunctionErrors.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ function hasNonMathcingGenericType<T>(a: string): a is T[] {
5050
let a: A;
5151
let b: B;
5252

53+
declare function isA(p1): p1 is A;
5354
declare function isB(p1): p1 is B;
5455
declare function isC(p1): p1 is C;
5556
declare function funA(p1: any, p2: any): p1 is B;
@@ -71,8 +72,10 @@ if (hasNoTypeGuard(a)) {
7172
}
7273

7374
// Type predicate type is not assignable
74-
declare function acceptingDifferentSignatureTypeGuardFunction(p1: (p1) => p1 is B);
75+
declare function acceptingDifferentSignatureTypeGuardFunction(p1: (p1) => p1 is A);
7576
acceptingDifferentSignatureTypeGuardFunction(isC);
77+
declare function acceptingDifferentSignatureTypeGuardFunction2(p1: (p1) => p1 is C);
78+
acceptingDifferentSignatureTypeGuardFunction2(isA);
7679

7780
// Boolean not assignable to type guard
7881
var assign1: (p1, p2) => p1 is A;
@@ -240,6 +243,7 @@ if (hasNoTypeGuard(a)) {
240243
a.propB;
241244
}
242245
acceptingDifferentSignatureTypeGuardFunction(isC);
246+
acceptingDifferentSignatureTypeGuardFunction2(isA);
243247
// Boolean not assignable to type guard
244248
var assign1;
245249
assign1 = function (p1, p2) {

0 commit comments

Comments
 (0)