Skip to content

Commit 3d6650e

Browse files
Fix #38608 (#38610)
* Fix #38608 * Work for narrowed non-unions * Add comment
1 parent 79d3058 commit 3d6650e

9 files changed

+369
-11
lines changed

src/compiler/checker.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22963,7 +22963,8 @@ namespace ts {
2296322963
}
2296422964

2296522965
function narrowByInKeyword(type: Type, literal: LiteralExpression, assumeTrue: boolean) {
22966-
if (type.flags & (TypeFlags.Union | TypeFlags.Object)
22966+
if (type.flags & TypeFlags.Union
22967+
|| type.flags & TypeFlags.Object && declaredType !== type
2296722968
|| isThisTypeParameter(type)
2296822969
|| type.flags & TypeFlags.Intersection && every((type as IntersectionType).types, t => t.symbol !== globalThisSymbol)) {
2296922970
const propName = escapeLeadingUnderscores(literal.text);

tests/baselines/reference/fixSignatureCaching.errors.txt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ tests/cases/conformance/fixSignatureCaching.ts(284,10): error TS2339: Property '
33
tests/cases/conformance/fixSignatureCaching.ts(293,10): error TS2339: Property 'FALLBACK_PHONE' does not exist on type '{}'.
44
tests/cases/conformance/fixSignatureCaching.ts(294,10): error TS2339: Property 'FALLBACK_TABLET' does not exist on type '{}'.
55
tests/cases/conformance/fixSignatureCaching.ts(295,10): error TS2339: Property 'FALLBACK_MOBILE' does not exist on type '{}'.
6-
tests/cases/conformance/fixSignatureCaching.ts(301,17): error TS2339: Property 'isArray' does not exist on type 'never'.
76
tests/cases/conformance/fixSignatureCaching.ts(330,74): error TS2339: Property 'mobileDetectRules' does not exist on type '{}'.
87
tests/cases/conformance/fixSignatureCaching.ts(369,10): error TS2339: Property 'findMatch' does not exist on type '{}'.
98
tests/cases/conformance/fixSignatureCaching.ts(387,10): error TS2339: Property 'findMatches' does not exist on type '{}'.
@@ -59,7 +58,7 @@ tests/cases/conformance/fixSignatureCaching.ts(981,16): error TS2304: Cannot fin
5958
tests/cases/conformance/fixSignatureCaching.ts(983,44): error TS2339: Property 'MobileDetect' does not exist on type 'Window & typeof globalThis'.
6059

6160

62-
==== tests/cases/conformance/fixSignatureCaching.ts (59 errors) ====
61+
==== tests/cases/conformance/fixSignatureCaching.ts (58 errors) ====
6362
// Repro from #10697
6463

6564
(function (define, undefined) {
@@ -371,8 +370,6 @@ tests/cases/conformance/fixSignatureCaching.ts(983,44): error TS2339: Property '
371370
isArray = 'isArray' in Array
372371
? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; }
373372
: Array.isArray;
374-
~~~~~~~
375-
!!! error TS2339: Property 'isArray' does not exist on type 'never'.
376373

377374
function equalIC(a, b) {
378375
return a != null && b != null && a.toLowerCase() === b.toLowerCase();

tests/baselines/reference/fixSignatureCaching.symbols

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,9 @@ define(function () {
825825
>value : Symbol(value, Decl(fixSignatureCaching.ts, 299, 20))
826826

827827
: Array.isArray;
828+
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
828829
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
830+
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
829831

830832
function equalIC(a, b) {
831833
>equalIC : Symbol(equalIC, Decl(fixSignatureCaching.ts, 300, 24))

tests/baselines/reference/fixSignatureCaching.types

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,9 +1127,9 @@ define(function () {
11271127
>'[object Array]' : "[object Array]"
11281128

11291129
isArray = 'isArray' in Array
1130-
>isArray = 'isArray' in Array ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : Array.isArray : any
1130+
>isArray = 'isArray' in Array ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : Array.isArray : (value: any) => boolean
11311131
>isArray : any
1132-
>'isArray' in Array ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : Array.isArray : any
1132+
>'isArray' in Array ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : Array.isArray : (value: any) => boolean
11331133
>'isArray' in Array : boolean
11341134
>'isArray' : "isArray"
11351135
>Array : ArrayConstructor
@@ -1150,9 +1150,9 @@ define(function () {
11501150
>'[object Array]' : "[object Array]"
11511151

11521152
: Array.isArray;
1153-
>Array.isArray : any
1154-
>Array : never
1155-
>isArray : any
1153+
>Array.isArray : <T>(arg: {} | T) => arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]
1154+
>Array : ArrayConstructor
1155+
>isArray : <T>(arg: {} | T) => arg is T extends readonly any[] ? unknown extends T ? never : readonly any[] : any[]
11561156

11571157
function equalIC(a, b) {
11581158
>equalIC : (a: any, b: any) => boolean

tests/baselines/reference/inKeywordTypeguard.errors.txt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,46 @@ tests/cases/compiler/inKeywordTypeguard.ts(94,26): error TS2339: Property 'a' do
165165
let n: never = x;
166166
}
167167
}
168+
169+
// Repro from #38608
170+
declare const error: Error;
171+
if ('extra' in error) {
172+
error // Still Error
173+
} else {
174+
error // Error
175+
}
176+
177+
function narrowsToNever(x: { l: number } | { r: number }) {
178+
let v: number;
179+
if ("l" in x) {
180+
v = x.l;
181+
}
182+
else if ("r" in x) {
183+
v = x.r;
184+
}
185+
else {
186+
v = x
187+
}
188+
return v;
189+
}
190+
191+
type AOrB = { aProp: number } | { bProp: number };
192+
declare function isAOrB(x: unknown): x is AOrB;
193+
194+
declare var x: unknown;
195+
if (isAOrB(x)) {
196+
if ("aProp" in x) {
197+
x.aProp;
198+
}
199+
else if ("bProp" in x) {
200+
x.bProp;
201+
}
202+
// x is never because of the type predicate from unknown
203+
else if ("cProp" in x) {
204+
const _never: never = x;
205+
}
206+
}
207+
168208
function negativeIntersectionTest() {
169209
if ("ontouchstart" in window) {
170210
window.ontouchstart

tests/baselines/reference/inKeywordTypeguard.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,46 @@ function positiveIntersectionTest(x: { a: string } & { b: string }) {
104104
let n: never = x;
105105
}
106106
}
107+
108+
// Repro from #38608
109+
declare const error: Error;
110+
if ('extra' in error) {
111+
error // Still Error
112+
} else {
113+
error // Error
114+
}
115+
116+
function narrowsToNever(x: { l: number } | { r: number }) {
117+
let v: number;
118+
if ("l" in x) {
119+
v = x.l;
120+
}
121+
else if ("r" in x) {
122+
v = x.r;
123+
}
124+
else {
125+
v = x
126+
}
127+
return v;
128+
}
129+
130+
type AOrB = { aProp: number } | { bProp: number };
131+
declare function isAOrB(x: unknown): x is AOrB;
132+
133+
declare var x: unknown;
134+
if (isAOrB(x)) {
135+
if ("aProp" in x) {
136+
x.aProp;
137+
}
138+
else if ("bProp" in x) {
139+
x.bProp;
140+
}
141+
// x is never because of the type predicate from unknown
142+
else if ("cProp" in x) {
143+
const _never: never = x;
144+
}
145+
}
146+
107147
function negativeIntersectionTest() {
108148
if ("ontouchstart" in window) {
109149
window.ontouchstart
@@ -252,6 +292,37 @@ function positiveIntersectionTest(x) {
252292
var n = x;
253293
}
254294
}
295+
if ('extra' in error) {
296+
error; // Still Error
297+
}
298+
else {
299+
error; // Error
300+
}
301+
function narrowsToNever(x) {
302+
var v;
303+
if ("l" in x) {
304+
v = x.l;
305+
}
306+
else if ("r" in x) {
307+
v = x.r;
308+
}
309+
else {
310+
v = x;
311+
}
312+
return v;
313+
}
314+
if (isAOrB(x)) {
315+
if ("aProp" in x) {
316+
x.aProp;
317+
}
318+
else if ("bProp" in x) {
319+
x.bProp;
320+
}
321+
// x is never because of the type predicate from unknown
322+
else if ("cProp" in x) {
323+
var _never = x;
324+
}
325+
}
255326
function negativeIntersectionTest() {
256327
if ("ontouchstart" in window) {
257328
window.ontouchstart;

tests/baselines/reference/inKeywordTypeguard.symbols

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,8 +261,105 @@ function positiveIntersectionTest(x: { a: string } & { b: string }) {
261261
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 98, 34))
262262
}
263263
}
264+
265+
// Repro from #38608
266+
declare const error: Error;
267+
>error : Symbol(error, Decl(inKeywordTypeguard.ts, 107, 13))
268+
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
269+
270+
if ('extra' in error) {
271+
>error : Symbol(error, Decl(inKeywordTypeguard.ts, 107, 13))
272+
273+
error // Still Error
274+
>error : Symbol(error, Decl(inKeywordTypeguard.ts, 107, 13))
275+
276+
} else {
277+
error // Error
278+
>error : Symbol(error, Decl(inKeywordTypeguard.ts, 107, 13))
279+
}
280+
281+
function narrowsToNever(x: { l: number } | { r: number }) {
282+
>narrowsToNever : Symbol(narrowsToNever, Decl(inKeywordTypeguard.ts, 112, 1))
283+
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 114, 24))
284+
>l : Symbol(l, Decl(inKeywordTypeguard.ts, 114, 28))
285+
>r : Symbol(r, Decl(inKeywordTypeguard.ts, 114, 44))
286+
287+
let v: number;
288+
>v : Symbol(v, Decl(inKeywordTypeguard.ts, 115, 7))
289+
290+
if ("l" in x) {
291+
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 114, 24))
292+
293+
v = x.l;
294+
>v : Symbol(v, Decl(inKeywordTypeguard.ts, 115, 7))
295+
>x.l : Symbol(l, Decl(inKeywordTypeguard.ts, 114, 28))
296+
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 114, 24))
297+
>l : Symbol(l, Decl(inKeywordTypeguard.ts, 114, 28))
298+
}
299+
else if ("r" in x) {
300+
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 114, 24))
301+
302+
v = x.r;
303+
>v : Symbol(v, Decl(inKeywordTypeguard.ts, 115, 7))
304+
>x.r : Symbol(r, Decl(inKeywordTypeguard.ts, 114, 44))
305+
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 114, 24))
306+
>r : Symbol(r, Decl(inKeywordTypeguard.ts, 114, 44))
307+
}
308+
else {
309+
v = x
310+
>v : Symbol(v, Decl(inKeywordTypeguard.ts, 115, 7))
311+
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 114, 24))
312+
}
313+
return v;
314+
>v : Symbol(v, Decl(inKeywordTypeguard.ts, 115, 7))
315+
}
316+
317+
type AOrB = { aProp: number } | { bProp: number };
318+
>AOrB : Symbol(AOrB, Decl(inKeywordTypeguard.ts, 126, 1))
319+
>aProp : Symbol(aProp, Decl(inKeywordTypeguard.ts, 128, 13))
320+
>bProp : Symbol(bProp, Decl(inKeywordTypeguard.ts, 128, 33))
321+
322+
declare function isAOrB(x: unknown): x is AOrB;
323+
>isAOrB : Symbol(isAOrB, Decl(inKeywordTypeguard.ts, 128, 50))
324+
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 129, 24))
325+
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 129, 24))
326+
>AOrB : Symbol(AOrB, Decl(inKeywordTypeguard.ts, 126, 1))
327+
328+
declare var x: unknown;
329+
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 131, 11))
330+
331+
if (isAOrB(x)) {
332+
>isAOrB : Symbol(isAOrB, Decl(inKeywordTypeguard.ts, 128, 50))
333+
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 131, 11))
334+
335+
if ("aProp" in x) {
336+
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 131, 11))
337+
338+
x.aProp;
339+
>x.aProp : Symbol(aProp, Decl(inKeywordTypeguard.ts, 128, 13))
340+
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 131, 11))
341+
>aProp : Symbol(aProp, Decl(inKeywordTypeguard.ts, 128, 13))
342+
}
343+
else if ("bProp" in x) {
344+
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 131, 11))
345+
346+
x.bProp;
347+
>x.bProp : Symbol(bProp, Decl(inKeywordTypeguard.ts, 128, 33))
348+
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 131, 11))
349+
>bProp : Symbol(bProp, Decl(inKeywordTypeguard.ts, 128, 33))
350+
}
351+
// x is never because of the type predicate from unknown
352+
else if ("cProp" in x) {
353+
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 131, 11))
354+
355+
const _never: never = x;
356+
>_never : Symbol(_never, Decl(inKeywordTypeguard.ts, 141, 13))
357+
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 131, 11))
358+
}
359+
}
360+
264361
function negativeIntersectionTest() {
265-
>negativeIntersectionTest : Symbol(negativeIntersectionTest, Decl(inKeywordTypeguard.ts, 104, 1))
362+
>negativeIntersectionTest : Symbol(negativeIntersectionTest, Decl(inKeywordTypeguard.ts, 143, 1))
266363

267364
if ("ontouchstart" in window) {
268365
>window : Symbol(window, Decl(lib.dom.d.ts, --, --))

0 commit comments

Comments
 (0)