narrow type for generic variables inside TypeQuery (#48434)

This commit is contained in:
Zzzen
2022-04-06 00:33:19 +08:00
committed by GitHub
parent 25aecd4c3e
commit 370d34cdca
6 changed files with 222 additions and 0 deletions

View File

@@ -25311,6 +25311,7 @@ namespace ts {
// a generic type without a nullable constraint and x is a generic type. This is because when both obj
// and x are of generic types T and K, we want the resulting type to be T[K].
return parent.kind === SyntaxKind.PropertyAccessExpression ||
parent.kind === SyntaxKind.QualifiedName ||
parent.kind === SyntaxKind.CallExpression && (parent as CallExpression).expression === node ||
parent.kind === SyntaxKind.ElementAccessExpression && (parent as ElementAccessExpression).expression === node &&
!(someType(type, isGenericTypeWithoutNullableConstraint) && isGenericIndexType(getTypeOfExpression((parent as ElementAccessExpression).argumentExpression)));

View File

@@ -71,4 +71,25 @@ tests/cases/compiler/narrowingOfQualifiedNames.ts(38,29): error TS2532: Object i
}
}
}
}
// Repro from #48289
type Fish = { type: 'fish', hasFins: true }
type Dog = { type: 'dog', saysWoof: true }
type Pet = Fish | Dog;
function handleDogBroken<PetType extends Pet>(pet: PetType) {
if(pet.type === 'dog') {
const _okay1 = pet.saysWoof;
const _okay2: typeof pet.saysWoof = pet.saysWoof;
}
}
function handleDogWorking(pet: Pet) {
if(pet.type === 'dog') {
const _okay1 = pet.saysWoof;
const _okay2: typeof pet.saysWoof = pet.saysWoof;
}
}

View File

@@ -63,6 +63,27 @@ function init2(foo: DeepOptional) {
}
}
}
}
// Repro from #48289
type Fish = { type: 'fish', hasFins: true }
type Dog = { type: 'dog', saysWoof: true }
type Pet = Fish | Dog;
function handleDogBroken<PetType extends Pet>(pet: PetType) {
if(pet.type === 'dog') {
const _okay1 = pet.saysWoof;
const _okay2: typeof pet.saysWoof = pet.saysWoof;
}
}
function handleDogWorking(pet: Pet) {
if(pet.type === 'dog') {
const _okay1 = pet.saysWoof;
const _okay2: typeof pet.saysWoof = pet.saysWoof;
}
}
//// [narrowingOfQualifiedNames.js]
@@ -94,3 +115,15 @@ function init2(foo) {
}
}
}
function handleDogBroken(pet) {
if (pet.type === 'dog') {
var _okay1 = pet.saysWoof;
var _okay2 = pet.saysWoof;
}
}
function handleDogWorking(pet) {
if (pet.type === 'dog') {
var _okay1 = pet.saysWoof;
var _okay2 = pet.saysWoof;
}
}

View File

@@ -253,3 +253,76 @@ function init2(foo: DeepOptional) {
}
}
}
// Repro from #48289
type Fish = { type: 'fish', hasFins: true }
>Fish : Symbol(Fish, Decl(narrowingOfQualifiedNames.ts, 64, 1))
>type : Symbol(type, Decl(narrowingOfQualifiedNames.ts, 68, 13))
>hasFins : Symbol(hasFins, Decl(narrowingOfQualifiedNames.ts, 68, 27))
type Dog = { type: 'dog', saysWoof: true }
>Dog : Symbol(Dog, Decl(narrowingOfQualifiedNames.ts, 68, 43))
>type : Symbol(type, Decl(narrowingOfQualifiedNames.ts, 69, 12))
>saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
type Pet = Fish | Dog;
>Pet : Symbol(Pet, Decl(narrowingOfQualifiedNames.ts, 69, 42))
>Fish : Symbol(Fish, Decl(narrowingOfQualifiedNames.ts, 64, 1))
>Dog : Symbol(Dog, Decl(narrowingOfQualifiedNames.ts, 68, 43))
function handleDogBroken<PetType extends Pet>(pet: PetType) {
>handleDogBroken : Symbol(handleDogBroken, Decl(narrowingOfQualifiedNames.ts, 71, 22))
>PetType : Symbol(PetType, Decl(narrowingOfQualifiedNames.ts, 73, 25))
>Pet : Symbol(Pet, Decl(narrowingOfQualifiedNames.ts, 69, 42))
>pet : Symbol(pet, Decl(narrowingOfQualifiedNames.ts, 73, 46))
>PetType : Symbol(PetType, Decl(narrowingOfQualifiedNames.ts, 73, 25))
if(pet.type === 'dog') {
>pet.type : Symbol(type, Decl(narrowingOfQualifiedNames.ts, 68, 13), Decl(narrowingOfQualifiedNames.ts, 69, 12))
>pet : Symbol(pet, Decl(narrowingOfQualifiedNames.ts, 73, 46))
>type : Symbol(type, Decl(narrowingOfQualifiedNames.ts, 68, 13), Decl(narrowingOfQualifiedNames.ts, 69, 12))
const _okay1 = pet.saysWoof;
>_okay1 : Symbol(_okay1, Decl(narrowingOfQualifiedNames.ts, 75, 13))
>pet.saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
>pet : Symbol(pet, Decl(narrowingOfQualifiedNames.ts, 73, 46))
>saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
const _okay2: typeof pet.saysWoof = pet.saysWoof;
>_okay2 : Symbol(_okay2, Decl(narrowingOfQualifiedNames.ts, 76, 13))
>pet.saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
>pet : Symbol(pet, Decl(narrowingOfQualifiedNames.ts, 73, 46))
>saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
>pet.saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
>pet : Symbol(pet, Decl(narrowingOfQualifiedNames.ts, 73, 46))
>saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
}
}
function handleDogWorking(pet: Pet) {
>handleDogWorking : Symbol(handleDogWorking, Decl(narrowingOfQualifiedNames.ts, 78, 1))
>pet : Symbol(pet, Decl(narrowingOfQualifiedNames.ts, 80, 26))
>Pet : Symbol(Pet, Decl(narrowingOfQualifiedNames.ts, 69, 42))
if(pet.type === 'dog') {
>pet.type : Symbol(type, Decl(narrowingOfQualifiedNames.ts, 68, 13), Decl(narrowingOfQualifiedNames.ts, 69, 12))
>pet : Symbol(pet, Decl(narrowingOfQualifiedNames.ts, 80, 26))
>type : Symbol(type, Decl(narrowingOfQualifiedNames.ts, 68, 13), Decl(narrowingOfQualifiedNames.ts, 69, 12))
const _okay1 = pet.saysWoof;
>_okay1 : Symbol(_okay1, Decl(narrowingOfQualifiedNames.ts, 82, 13))
>pet.saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
>pet : Symbol(pet, Decl(narrowingOfQualifiedNames.ts, 80, 26))
>saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
const _okay2: typeof pet.saysWoof = pet.saysWoof;
>_okay2 : Symbol(_okay2, Decl(narrowingOfQualifiedNames.ts, 83, 13))
>pet.saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
>pet : Symbol(pet, Decl(narrowingOfQualifiedNames.ts, 80, 26))
>saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
>pet.saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
>pet : Symbol(pet, Decl(narrowingOfQualifiedNames.ts, 80, 26))
>saysWoof : Symbol(saysWoof, Decl(narrowingOfQualifiedNames.ts, 69, 25))
}
}

View File

@@ -257,3 +257,76 @@ function init2(foo: DeepOptional) {
}
}
}
// Repro from #48289
type Fish = { type: 'fish', hasFins: true }
>Fish : Fish
>type : "fish"
>hasFins : true
>true : true
type Dog = { type: 'dog', saysWoof: true }
>Dog : Dog
>type : "dog"
>saysWoof : true
>true : true
type Pet = Fish | Dog;
>Pet : Pet
function handleDogBroken<PetType extends Pet>(pet: PetType) {
>handleDogBroken : <PetType extends Pet>(pet: PetType) => void
>pet : PetType
if(pet.type === 'dog') {
>pet.type === 'dog' : boolean
>pet.type : "fish" | "dog"
>pet : Pet
>type : "fish" | "dog"
>'dog' : "dog"
const _okay1 = pet.saysWoof;
>_okay1 : true
>pet.saysWoof : true
>pet : Dog
>saysWoof : true
const _okay2: typeof pet.saysWoof = pet.saysWoof;
>_okay2 : true
>pet.saysWoof : true
>pet : Dog
>saysWoof : true
>pet.saysWoof : true
>pet : Dog
>saysWoof : true
}
}
function handleDogWorking(pet: Pet) {
>handleDogWorking : (pet: Pet) => void
>pet : Pet
if(pet.type === 'dog') {
>pet.type === 'dog' : boolean
>pet.type : "fish" | "dog"
>pet : Pet
>type : "fish" | "dog"
>'dog' : "dog"
const _okay1 = pet.saysWoof;
>_okay1 : true
>pet.saysWoof : true
>pet : Dog
>saysWoof : true
const _okay2: typeof pet.saysWoof = pet.saysWoof;
>_okay2 : true
>pet.saysWoof : true
>pet : Dog
>saysWoof : true
>pet.saysWoof : true
>pet : Dog
>saysWoof : true
}
}

View File

@@ -64,4 +64,25 @@ function init2(foo: DeepOptional) {
}
}
}
}
// Repro from #48289
type Fish = { type: 'fish', hasFins: true }
type Dog = { type: 'dog', saysWoof: true }
type Pet = Fish | Dog;
function handleDogBroken<PetType extends Pet>(pet: PetType) {
if(pet.type === 'dog') {
const _okay1 = pet.saysWoof;
const _okay2: typeof pet.saysWoof = pet.saysWoof;
}
}
function handleDogWorking(pet: Pet) {
if(pet.type === 'dog') {
const _okay1 = pet.saysWoof;
const _okay2: typeof pet.saysWoof = pet.saysWoof;
}
}