Skip to content

Commit

Permalink
support QualifiedName when narrowing inside loops (#43592)
Browse files Browse the repository at this point in the history
* support QualifiedName when narrowing inside loops

* add test

* narrow more qualified names

* handle `undefined` of `getFlowCacheKey `

* update comments in test
  • Loading branch information
Zzzen authored May 21, 2021
1 parent 14343be commit 756392c
Show file tree
Hide file tree
Showing 7 changed files with 755 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2518,7 +2518,7 @@ namespace ts {
}
return checkContextualIdentifier(node as Identifier);
case SyntaxKind.QualifiedName:
if (currentFlow && parent.kind === SyntaxKind.TypeQuery) {
if (currentFlow && isPartOfTypeQuery(node)) {
node.flowNode = currentFlow;
}
break;
Expand Down
3 changes: 3 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21955,6 +21955,9 @@ namespace ts {
case SyntaxKind.NonNullExpression:
case SyntaxKind.ParenthesizedExpression:
return getFlowCacheKey((node as NonNullExpression | ParenthesizedExpression).expression, declaredType, initialType, flowContainer);
case SyntaxKind.QualifiedName:
const left = getFlowCacheKey((node as QualifiedName).left, declaredType, initialType, flowContainer);
return left && left + "." + (node as QualifiedName).right.escapedText;
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ElementAccessExpression:
const propName = getAccessedPropertyName(node as AccessExpression);
Expand Down
74 changes: 74 additions & 0 deletions tests/baselines/reference/narrowingOfQualifiedNames.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
tests/cases/compiler/narrowingOfQualifiedNames.ts(33,25): error TS2532: Object is possibly 'undefined'.
tests/cases/compiler/narrowingOfQualifiedNames.ts(38,29): error TS2532: Object is possibly 'undefined'.


==== tests/cases/compiler/narrowingOfQualifiedNames.ts (2 errors) ====
// Repro from #43411

interface IProperties {
foo?: {
aaa: string
bbb: string
}
}

function init(properties: IProperties) {
if (properties.foo) {
type FooOK = typeof properties.foo;
properties.foo; // type is { aaa: string; bbb: string; }
for (const x of [1, 2, 3]) {
properties.foo; // type is { aaa: string; bbb: string; }
type FooOrUndefined = typeof properties.foo; // type should be { aaa: string; bbb: string; }
}
}
}

interface DeepOptional {
a?: {
b?: {
c?: string
}
}
}

function init2(foo: DeepOptional) {
if (foo.a) {
type A = typeof foo.a;
type B = typeof foo.a.b;
type C = typeof foo.a.b.c;
~~~~~~~
!!! error TS2532: Object is possibly 'undefined'.

for(const _ of [1]) {
type A = typeof foo.a;
type B = typeof foo.a.b;
type C = typeof foo.a.b.c;
~~~~~~~
!!! error TS2532: Object is possibly 'undefined'.

if (foo.a.b) {
type A = typeof foo.a;
type B = typeof foo.a.b;
type C = typeof foo.a.b.c;

for(const _ of [1]) {
type A = typeof foo.a;
type B = typeof foo.a.b;
type C = typeof foo.a.b.c;

if (foo.a.b.c) {
type A = typeof foo.a;
type B = typeof foo.a.b;
type C = typeof foo.a.b.c;

for(const _ of [1]) {
type A = typeof foo.a;
type B = typeof foo.a.b;
type C = typeof foo.a.b.c;
}
}
}
}
}
}
}
96 changes: 96 additions & 0 deletions tests/baselines/reference/narrowingOfQualifiedNames.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
//// [narrowingOfQualifiedNames.ts]
// Repro from #43411

interface IProperties {
foo?: {
aaa: string
bbb: string
}
}

function init(properties: IProperties) {
if (properties.foo) {
type FooOK = typeof properties.foo;
properties.foo; // type is { aaa: string; bbb: string; }
for (const x of [1, 2, 3]) {
properties.foo; // type is { aaa: string; bbb: string; }
type FooOrUndefined = typeof properties.foo; // type should be { aaa: string; bbb: string; }
}
}
}

interface DeepOptional {
a?: {
b?: {
c?: string
}
}
}

function init2(foo: DeepOptional) {
if (foo.a) {
type A = typeof foo.a;
type B = typeof foo.a.b;
type C = typeof foo.a.b.c;

for(const _ of [1]) {
type A = typeof foo.a;
type B = typeof foo.a.b;
type C = typeof foo.a.b.c;

if (foo.a.b) {
type A = typeof foo.a;
type B = typeof foo.a.b;
type C = typeof foo.a.b.c;

for(const _ of [1]) {
type A = typeof foo.a;
type B = typeof foo.a.b;
type C = typeof foo.a.b.c;

if (foo.a.b.c) {
type A = typeof foo.a;
type B = typeof foo.a.b;
type C = typeof foo.a.b.c;

for(const _ of [1]) {
type A = typeof foo.a;
type B = typeof foo.a.b;
type C = typeof foo.a.b.c;
}
}
}
}
}
}
}

//// [narrowingOfQualifiedNames.js]
"use strict";
// Repro from #43411
function init(properties) {
if (properties.foo) {
properties.foo; // type is { aaa: string; bbb: string; }
for (var _i = 0, _a = [1, 2, 3]; _i < _a.length; _i++) {
var x = _a[_i];
properties.foo; // type is { aaa: string; bbb: string; }
}
}
}
function init2(foo) {
if (foo.a) {
for (var _i = 0, _a = [1]; _i < _a.length; _i++) {
var _ = _a[_i];
if (foo.a.b) {
for (var _b = 0, _c = [1]; _b < _c.length; _b++) {
var _1 = _c[_b];
if (foo.a.b.c) {
for (var _d = 0, _e = [1]; _d < _e.length; _d++) {
var _2 = _e[_d];
}
}
}
}
}
}
}
Loading

0 comments on commit 756392c

Please sign in to comment.