Skip to content

Commit 370d34c

Browse files
authored
narrow type for generic variables inside TypeQuery (#48434)
1 parent 25aecd4 commit 370d34c

File tree

6 files changed

+222
-0
lines changed

6 files changed

+222
-0
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25311,6 +25311,7 @@ namespace ts {
2531125311
// a generic type without a nullable constraint and x is a generic type. This is because when both obj
2531225312
// and x are of generic types T and K, we want the resulting type to be T[K].
2531325313
return parent.kind === SyntaxKind.PropertyAccessExpression ||
25314+
parent.kind === SyntaxKind.QualifiedName ||
2531425315
parent.kind === SyntaxKind.CallExpression && (parent as CallExpression).expression === node ||
2531525316
parent.kind === SyntaxKind.ElementAccessExpression && (parent as ElementAccessExpression).expression === node &&
2531625317
!(someType(type, isGenericTypeWithoutNullableConstraint) && isGenericIndexType(getTypeOfExpression((parent as ElementAccessExpression).argumentExpression)));

tests/baselines/reference/narrowingOfQualifiedNames.errors.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,25 @@ tests/cases/compiler/narrowingOfQualifiedNames.ts(38,29): error TS2532: Object i
7171
}
7272
}
7373
}
74+
}
75+
76+
// Repro from #48289
77+
78+
type Fish = { type: 'fish', hasFins: true }
79+
type Dog = { type: 'dog', saysWoof: true }
80+
81+
type Pet = Fish | Dog;
82+
83+
function handleDogBroken<PetType extends Pet>(pet: PetType) {
84+
if(pet.type === 'dog') {
85+
const _okay1 = pet.saysWoof;
86+
const _okay2: typeof pet.saysWoof = pet.saysWoof;
87+
}
88+
}
89+
90+
function handleDogWorking(pet: Pet) {
91+
if(pet.type === 'dog') {
92+
const _okay1 = pet.saysWoof;
93+
const _okay2: typeof pet.saysWoof = pet.saysWoof;
94+
}
7495
}

tests/baselines/reference/narrowingOfQualifiedNames.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,27 @@ function init2(foo: DeepOptional) {
6363
}
6464
}
6565
}
66+
}
67+
68+
// Repro from #48289
69+
70+
type Fish = { type: 'fish', hasFins: true }
71+
type Dog = { type: 'dog', saysWoof: true }
72+
73+
type Pet = Fish | Dog;
74+
75+
function handleDogBroken<PetType extends Pet>(pet: PetType) {
76+
if(pet.type === 'dog') {
77+
const _okay1 = pet.saysWoof;
78+
const _okay2: typeof pet.saysWoof = pet.saysWoof;
79+
}
80+
}
81+
82+
function handleDogWorking(pet: Pet) {
83+
if(pet.type === 'dog') {
84+
const _okay1 = pet.saysWoof;
85+
const _okay2: typeof pet.saysWoof = pet.saysWoof;
86+
}
6687
}
6788

6889
//// [narrowingOfQualifiedNames.js]
@@ -94,3 +115,15 @@ function init2(foo) {
94115
}
95116
}
96117
}
118+
function handleDogBroken(pet) {
119+
if (pet.type === 'dog') {
120+
var _okay1 = pet.saysWoof;
121+
var _okay2 = pet.saysWoof;
122+
}
123+
}
124+
function handleDogWorking(pet) {
125+
if (pet.type === 'dog') {
126+
var _okay1 = pet.saysWoof;
127+
var _okay2 = pet.saysWoof;
128+
}
129+
}

tests/baselines/reference/narrowingOfQualifiedNames.symbols

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,3 +253,76 @@ function init2(foo: DeepOptional) {
253253
}
254254
}
255255
}
256+
257+
// Repro from #48289
258+
259+
type Fish = { type: 'fish', hasFins: true }
260+
>Fish : Symbol(Fish, Decl(narrowingOfQualifiedNames.ts, 64, 1))
261+
>type : Symbol(type, Decl(narrowingOfQualifiedNames.ts, 68, 13))
262+
>hasFins : Symbol(hasFins, Decl(narrowingOfQualifiedNames.ts, 68, 27))
263+
264+
type Dog = { type: 'dog', saysWoof: true }
265+
>Dog : Symbol(Dog, Decl(narrowingOfQualifiedNames.ts, 68, 43))
266+
>type : Symbol(type, Decl(narrowingOfQualifiedNames.ts, 69, 12))
267+
>saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
268+
269+
type Pet = Fish | Dog;
270+
>Pet : Symbol(Pet, Decl(narrowingOfQualifiedNames.ts, 69, 42))
271+
>Fish : Symbol(Fish, Decl(narrowingOfQualifiedNames.ts, 64, 1))
272+
>Dog : Symbol(Dog, Decl(narrowingOfQualifiedNames.ts, 68, 43))
273+
274+
function handleDogBroken<PetType extends Pet>(pet: PetType) {
275+
>handleDogBroken : Symbol(handleDogBroken, Decl(narrowingOfQualifiedNames.ts, 71, 22))
276+
>PetType : Symbol(PetType, Decl(narrowingOfQualifiedNames.ts, 73, 25))
277+
>Pet : Symbol(Pet, Decl(narrowingOfQualifiedNames.ts, 69, 42))
278+
>pet : Symbol(pet, Decl(narrowingOfQualifiedNames.ts, 73, 46))
279+
>PetType : Symbol(PetType, Decl(narrowingOfQualifiedNames.ts, 73, 25))
280+
281+
if(pet.type === 'dog') {
282+
>pet.type : Symbol(type, Decl(narrowingOfQualifiedNames.ts, 68, 13), Decl(narrowingOfQualifiedNames.ts, 69, 12))
283+
>pet : Symbol(pet, Decl(narrowingOfQualifiedNames.ts, 73, 46))
284+
>type : Symbol(type, Decl(narrowingOfQualifiedNames.ts, 68, 13), Decl(narrowingOfQualifiedNames.ts, 69, 12))
285+
286+
const _okay1 = pet.saysWoof;
287+
>_okay1 : Symbol(_okay1, Decl(narrowingOfQualifiedNames.ts, 75, 13))
288+
>pet.saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
289+
>pet : Symbol(pet, Decl(narrowingOfQualifiedNames.ts, 73, 46))
290+
>saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
291+
292+
const _okay2: typeof pet.saysWoof = pet.saysWoof;
293+
>_okay2 : Symbol(_okay2, Decl(narrowingOfQualifiedNames.ts, 76, 13))
294+
>pet.saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
295+
>pet : Symbol(pet, Decl(narrowingOfQualifiedNames.ts, 73, 46))
296+
>saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
297+
>pet.saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
298+
>pet : Symbol(pet, Decl(narrowingOfQualifiedNames.ts, 73, 46))
299+
>saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
300+
}
301+
}
302+
303+
function handleDogWorking(pet: Pet) {
304+
>handleDogWorking : Symbol(handleDogWorking, Decl(narrowingOfQualifiedNames.ts, 78, 1))
305+
>pet : Symbol(pet, Decl(narrowingOfQualifiedNames.ts, 80, 26))
306+
>Pet : Symbol(Pet, Decl(narrowingOfQualifiedNames.ts, 69, 42))
307+
308+
if(pet.type === 'dog') {
309+
>pet.type : Symbol(type, Decl(narrowingOfQualifiedNames.ts, 68, 13), Decl(narrowingOfQualifiedNames.ts, 69, 12))
310+
>pet : Symbol(pet, Decl(narrowingOfQualifiedNames.ts, 80, 26))
311+
>type : Symbol(type, Decl(narrowingOfQualifiedNames.ts, 68, 13), Decl(narrowingOfQualifiedNames.ts, 69, 12))
312+
313+
const _okay1 = pet.saysWoof;
314+
>_okay1 : Symbol(_okay1, Decl(narrowingOfQualifiedNames.ts, 82, 13))
315+
>pet.saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
316+
>pet : Symbol(pet, Decl(narrowingOfQualifiedNames.ts, 80, 26))
317+
>saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
318+
319+
const _okay2: typeof pet.saysWoof = pet.saysWoof;
320+
>_okay2 : Symbol(_okay2, Decl(narrowingOfQualifiedNames.ts, 83, 13))
321+
>pet.saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
322+
>pet : Symbol(pet, Decl(narrowingOfQualifiedNames.ts, 80, 26))
323+
>saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
324+
>pet.saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
325+
>pet : Symbol(pet, Decl(narrowingOfQualifiedNames.ts, 80, 26))
326+
>saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
327+
}
328+
}

tests/baselines/reference/narrowingOfQualifiedNames.types

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,3 +257,76 @@ function init2(foo: DeepOptional) {
257257
}
258258
}
259259
}
260+
261+
// Repro from #48289
262+
263+
type Fish = { type: 'fish', hasFins: true }
264+
>Fish : Fish
265+
>type : "fish"
266+
>hasFins : true
267+
>true : true
268+
269+
type Dog = { type: 'dog', saysWoof: true }
270+
>Dog : Dog
271+
>type : "dog"
272+
>saysWoof : true
273+
>true : true
274+
275+
type Pet = Fish | Dog;
276+
>Pet : Pet
277+
278+
function handleDogBroken<PetType extends Pet>(pet: PetType) {
279+
>handleDogBroken : <PetType extends Pet>(pet: PetType) => void
280+
>pet : PetType
281+
282+
if(pet.type === 'dog') {
283+
>pet.type === 'dog' : boolean
284+
>pet.type : "fish" | "dog"
285+
>pet : Pet
286+
>type : "fish" | "dog"
287+
>'dog' : "dog"
288+
289+
const _okay1 = pet.saysWoof;
290+
>_okay1 : true
291+
>pet.saysWoof : true
292+
>pet : Dog
293+
>saysWoof : true
294+
295+
const _okay2: typeof pet.saysWoof = pet.saysWoof;
296+
>_okay2 : true
297+
>pet.saysWoof : true
298+
>pet : Dog
299+
>saysWoof : true
300+
>pet.saysWoof : true
301+
>pet : Dog
302+
>saysWoof : true
303+
}
304+
}
305+
306+
function handleDogWorking(pet: Pet) {
307+
>handleDogWorking : (pet: Pet) => void
308+
>pet : Pet
309+
310+
if(pet.type === 'dog') {
311+
>pet.type === 'dog' : boolean
312+
>pet.type : "fish" | "dog"
313+
>pet : Pet
314+
>type : "fish" | "dog"
315+
>'dog' : "dog"
316+
317+
const _okay1 = pet.saysWoof;
318+
>_okay1 : true
319+
>pet.saysWoof : true
320+
>pet : Dog
321+
>saysWoof : true
322+
323+
const _okay2: typeof pet.saysWoof = pet.saysWoof;
324+
>_okay2 : true
325+
>pet.saysWoof : true
326+
>pet : Dog
327+
>saysWoof : true
328+
>pet.saysWoof : true
329+
>pet : Dog
330+
>saysWoof : true
331+
}
332+
}

tests/cases/compiler/narrowingOfQualifiedNames.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,25 @@ function init2(foo: DeepOptional) {
6464
}
6565
}
6666
}
67+
}
68+
69+
// Repro from #48289
70+
71+
type Fish = { type: 'fish', hasFins: true }
72+
type Dog = { type: 'dog', saysWoof: true }
73+
74+
type Pet = Fish | Dog;
75+
76+
function handleDogBroken<PetType extends Pet>(pet: PetType) {
77+
if(pet.type === 'dog') {
78+
const _okay1 = pet.saysWoof;
79+
const _okay2: typeof pet.saysWoof = pet.saysWoof;
80+
}
81+
}
82+
83+
function handleDogWorking(pet: Pet) {
84+
if(pet.type === 'dog') {
85+
const _okay1 = pet.saysWoof;
86+
const _okay2: typeof pet.saysWoof = pet.saysWoof;
87+
}
6788
}

0 commit comments

Comments
 (0)