Skip to content

Commit

Permalink
fix 10530
Browse files Browse the repository at this point in the history
  • Loading branch information
easyrider committed Sep 30, 2021
1 parent 5ef0439 commit 44a8d67
Show file tree
Hide file tree
Showing 11 changed files with 238 additions and 13 deletions.
2 changes: 1 addition & 1 deletion src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -889,7 +889,7 @@ namespace ts {
return isDottedName(expr)
|| (isPropertyAccessExpression(expr) || isNonNullExpression(expr) || isParenthesizedExpression(expr)) && isNarrowableReference(expr.expression)
|| isBinaryExpression(expr) && expr.operatorToken.kind === SyntaxKind.CommaToken && isNarrowableReference(expr.right)
|| isElementAccessExpression(expr) && isStringOrNumericLiteralLike(expr.argumentExpression) && isNarrowableReference(expr.expression)
|| isElementAccessExpression(expr) && ((isStringOrNumericLiteralLike(expr.argumentExpression) && isNarrowableReference(expr.expression)) || isIdentifier(expr.argumentExpression))
|| isAssignmentExpression(expr) && isNarrowableReference(expr.left);
}

Expand Down
5 changes: 5 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32621,6 +32621,11 @@ namespace ts {
case SyntaxKind.ExclamationEqualsToken:
case SyntaxKind.EqualsEqualsEqualsToken:
case SyntaxKind.ExclamationEqualsEqualsToken:
if (isPropertyAccessExpression(left) &&
isElementAccessExpression(left.expression) &&
isIdentifier(left.expression.expression)) {
return booleanType;
}
reportOperatorErrorUnless((left, right) => isTypeEqualityComparableTo(left, right) || isTypeEqualityComparableTo(right, left));
return booleanType;

Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/controlFlowOptionalChain.types
Original file line number Diff line number Diff line change
Expand Up @@ -2057,11 +2057,11 @@ while (arr[i]?.tag === "left") {

if (arr[i]?.tag === "right") {
>arr[i]?.tag === "right" : boolean
>arr[i]?.tag : "left" | "right"
>arr[i]?.tag : "left"
>arr[i] : { tag: "left" | "right"; }
>arr : { tag: "left" | "right"; }[]
>i : number
>tag : "left" | "right"
>tag : "left"
>"right" : "right"

console.log("I should ALSO be reachable");
Expand Down
10 changes: 5 additions & 5 deletions tests/baselines/reference/incrementOnNullAssertion.types
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,21 @@ if (foo[x] === undefined) {
}
else {
let nu = foo[x]
>nu : number | undefined
>foo[x] : number | undefined
>nu : number
>foo[x] : number
>foo : Dictionary<number>
>x : "bar"

let n = foo[x]
>n : number | undefined
>foo[x] : number | undefined
>n : number
>foo[x] : number
>foo : Dictionary<number>
>x : "bar"

foo[x]!++
>foo[x]!++ : number
>foo[x]! : number
>foo[x] : number | undefined
>foo[x] : number
>foo : Dictionary<number>
>x : "bar"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
tests/cases/compiler/narrowingByNonLiteralIndexedAccess.ts(14,1): error TS2532: Object is possibly 'undefined'.
tests/cases/compiler/narrowingByNonLiteralIndexedAccess.ts(17,1): error TS2532: Object is possibly 'undefined'.


==== tests/cases/compiler/narrowingByNonLiteralIndexedAccess.ts (2 errors) ====
interface IEye {
visibility: number | undefined
}

interface IPirate {
hands: number | undefined,
eyes: IEye[]
}

const pirates: IPirate[] = [];

const index: number = 1;

pirates[index].hands++;
~~~~~~~~~~~~~~~~~~~~
!!! error TS2532: Object is possibly 'undefined'.
if (pirates[index].hands) pirates[index].hands++;

pirates[index].eyes[index].visibility++;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2532: Object is possibly 'undefined'.
if (pirates[index].eyes[index].visibility) pirates[index].eyes[index].visibility++;

31 changes: 31 additions & 0 deletions tests/baselines/reference/narrowingByNonLiteralIndexedAccess.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//// [narrowingByNonLiteralIndexedAccess.ts]
interface IEye {
visibility: number | undefined
}

interface IPirate {
hands: number | undefined,
eyes: IEye[]
}

const pirates: IPirate[] = [];

const index: number = 1;

pirates[index].hands++;
if (pirates[index].hands) pirates[index].hands++;

pirates[index].eyes[index].visibility++;
if (pirates[index].eyes[index].visibility) pirates[index].eyes[index].visibility++;


//// [narrowingByNonLiteralIndexedAccess.js]
"use strict";
var pirates = [];
var index = 1;
pirates[index].hands++;
if (pirates[index].hands)
pirates[index].hands++;
pirates[index].eyes[index].visibility++;
if (pirates[index].eyes[index].visibility)
pirates[index].eyes[index].visibility++;
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
=== tests/cases/compiler/narrowingByNonLiteralIndexedAccess.ts ===
interface IEye {
>IEye : Symbol(IEye, Decl(narrowingByNonLiteralIndexedAccess.ts, 0, 0))

visibility: number | undefined
>visibility : Symbol(IEye.visibility, Decl(narrowingByNonLiteralIndexedAccess.ts, 0, 16))
}

interface IPirate {
>IPirate : Symbol(IPirate, Decl(narrowingByNonLiteralIndexedAccess.ts, 2, 1))

hands: number | undefined,
>hands : Symbol(IPirate.hands, Decl(narrowingByNonLiteralIndexedAccess.ts, 4, 19))

eyes: IEye[]
>eyes : Symbol(IPirate.eyes, Decl(narrowingByNonLiteralIndexedAccess.ts, 5, 30))
>IEye : Symbol(IEye, Decl(narrowingByNonLiteralIndexedAccess.ts, 0, 0))
}

const pirates: IPirate[] = [];
>pirates : Symbol(pirates, Decl(narrowingByNonLiteralIndexedAccess.ts, 9, 5))
>IPirate : Symbol(IPirate, Decl(narrowingByNonLiteralIndexedAccess.ts, 2, 1))

const index: number = 1;
>index : Symbol(index, Decl(narrowingByNonLiteralIndexedAccess.ts, 11, 5))

pirates[index].hands++;
>pirates[index].hands : Symbol(IPirate.hands, Decl(narrowingByNonLiteralIndexedAccess.ts, 4, 19))
>pirates : Symbol(pirates, Decl(narrowingByNonLiteralIndexedAccess.ts, 9, 5))
>index : Symbol(index, Decl(narrowingByNonLiteralIndexedAccess.ts, 11, 5))
>hands : Symbol(IPirate.hands, Decl(narrowingByNonLiteralIndexedAccess.ts, 4, 19))

if (pirates[index].hands) pirates[index].hands++;
>pirates[index].hands : Symbol(IPirate.hands, Decl(narrowingByNonLiteralIndexedAccess.ts, 4, 19))
>pirates : Symbol(pirates, Decl(narrowingByNonLiteralIndexedAccess.ts, 9, 5))
>index : Symbol(index, Decl(narrowingByNonLiteralIndexedAccess.ts, 11, 5))
>hands : Symbol(IPirate.hands, Decl(narrowingByNonLiteralIndexedAccess.ts, 4, 19))
>pirates[index].hands : Symbol(IPirate.hands, Decl(narrowingByNonLiteralIndexedAccess.ts, 4, 19))
>pirates : Symbol(pirates, Decl(narrowingByNonLiteralIndexedAccess.ts, 9, 5))
>index : Symbol(index, Decl(narrowingByNonLiteralIndexedAccess.ts, 11, 5))
>hands : Symbol(IPirate.hands, Decl(narrowingByNonLiteralIndexedAccess.ts, 4, 19))

pirates[index].eyes[index].visibility++;
>pirates[index].eyes[index].visibility : Symbol(IEye.visibility, Decl(narrowingByNonLiteralIndexedAccess.ts, 0, 16))
>pirates[index].eyes : Symbol(IPirate.eyes, Decl(narrowingByNonLiteralIndexedAccess.ts, 5, 30))
>pirates : Symbol(pirates, Decl(narrowingByNonLiteralIndexedAccess.ts, 9, 5))
>index : Symbol(index, Decl(narrowingByNonLiteralIndexedAccess.ts, 11, 5))
>eyes : Symbol(IPirate.eyes, Decl(narrowingByNonLiteralIndexedAccess.ts, 5, 30))
>index : Symbol(index, Decl(narrowingByNonLiteralIndexedAccess.ts, 11, 5))
>visibility : Symbol(IEye.visibility, Decl(narrowingByNonLiteralIndexedAccess.ts, 0, 16))

if (pirates[index].eyes[index].visibility) pirates[index].eyes[index].visibility++;
>pirates[index].eyes[index].visibility : Symbol(IEye.visibility, Decl(narrowingByNonLiteralIndexedAccess.ts, 0, 16))
>pirates[index].eyes : Symbol(IPirate.eyes, Decl(narrowingByNonLiteralIndexedAccess.ts, 5, 30))
>pirates : Symbol(pirates, Decl(narrowingByNonLiteralIndexedAccess.ts, 9, 5))
>index : Symbol(index, Decl(narrowingByNonLiteralIndexedAccess.ts, 11, 5))
>eyes : Symbol(IPirate.eyes, Decl(narrowingByNonLiteralIndexedAccess.ts, 5, 30))
>index : Symbol(index, Decl(narrowingByNonLiteralIndexedAccess.ts, 11, 5))
>visibility : Symbol(IEye.visibility, Decl(narrowingByNonLiteralIndexedAccess.ts, 0, 16))
>pirates[index].eyes[index].visibility : Symbol(IEye.visibility, Decl(narrowingByNonLiteralIndexedAccess.ts, 0, 16))
>pirates[index].eyes : Symbol(IPirate.eyes, Decl(narrowingByNonLiteralIndexedAccess.ts, 5, 30))
>pirates : Symbol(pirates, Decl(narrowingByNonLiteralIndexedAccess.ts, 9, 5))
>index : Symbol(index, Decl(narrowingByNonLiteralIndexedAccess.ts, 11, 5))
>eyes : Symbol(IPirate.eyes, Decl(narrowingByNonLiteralIndexedAccess.ts, 5, 30))
>index : Symbol(index, Decl(narrowingByNonLiteralIndexedAccess.ts, 11, 5))
>visibility : Symbol(IEye.visibility, Decl(narrowingByNonLiteralIndexedAccess.ts, 0, 16))

76 changes: 76 additions & 0 deletions tests/baselines/reference/narrowingByNonLiteralIndexedAccess.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
=== tests/cases/compiler/narrowingByNonLiteralIndexedAccess.ts ===
interface IEye {
visibility: number | undefined
>visibility : number | undefined
}

interface IPirate {
hands: number | undefined,
>hands : number | undefined

eyes: IEye[]
>eyes : IEye[]
}

const pirates: IPirate[] = [];
>pirates : IPirate[]
>[] : never[]

const index: number = 1;
>index : number
>1 : 1

pirates[index].hands++;
>pirates[index].hands++ : number
>pirates[index].hands : number | undefined
>pirates[index] : IPirate
>pirates : IPirate[]
>index : number
>hands : number | undefined

if (pirates[index].hands) pirates[index].hands++;
>pirates[index].hands : number | undefined
>pirates[index] : IPirate
>pirates : IPirate[]
>index : number
>hands : number | undefined
>pirates[index].hands++ : number
>pirates[index].hands : number
>pirates[index] : IPirate
>pirates : IPirate[]
>index : number
>hands : number

pirates[index].eyes[index].visibility++;
>pirates[index].eyes[index].visibility++ : number
>pirates[index].eyes[index].visibility : number | undefined
>pirates[index].eyes[index] : IEye
>pirates[index].eyes : IEye[]
>pirates[index] : IPirate
>pirates : IPirate[]
>index : number
>eyes : IEye[]
>index : number
>visibility : number | undefined

if (pirates[index].eyes[index].visibility) pirates[index].eyes[index].visibility++;
>pirates[index].eyes[index].visibility : number | undefined
>pirates[index].eyes[index] : IEye
>pirates[index].eyes : IEye[]
>pirates[index] : IPirate
>pirates : IPirate[]
>index : number
>eyes : IEye[]
>index : number
>visibility : number | undefined
>pirates[index].eyes[index].visibility++ : number
>pirates[index].eyes[index].visibility : number
>pirates[index].eyes[index] : IEye
>pirates[index].eyes : IEye[]
>pirates[index] : IPirate
>pirates : IPirate[]
>index : number
>eyes : IEye[]
>index : number
>visibility : number

6 changes: 2 additions & 4 deletions tests/baselines/reference/noUncheckedIndexedAccess.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ tests/cases/conformance/pedantic/noUncheckedIndexedAccess.ts(90,7): error TS2322
Type 'undefined' is not assignable to type 'string'.
tests/cases/conformance/pedantic/noUncheckedIndexedAccess.ts(98,5): error TS2322: Type 'undefined' is not assignable to type '{ [key: string]: string; a: string; b: string; }[Key]'.
Type 'undefined' is not assignable to type 'string'.
tests/cases/conformance/pedantic/noUncheckedIndexedAccess.ts(99,11): error TS2322: Type 'string | undefined' is not assignable to type 'string'.
Type 'undefined' is not assignable to type 'string'.
tests/cases/conformance/pedantic/noUncheckedIndexedAccess.ts(99,11): error TS2322: Type 'undefined' is not assignable to type 'string'.


==== tests/cases/conformance/pedantic/noUncheckedIndexedAccess.ts (31 errors) ====
Expand Down Expand Up @@ -201,8 +200,7 @@ tests/cases/conformance/pedantic/noUncheckedIndexedAccess.ts(99,11): error TS232
!!! error TS2322: Type 'undefined' is not assignable to type 'string'.
const v: string = myRecord2[key]; // Should error
~
!!! error TS2322: Type 'string | undefined' is not assignable to type 'string'.
!!! error TS2322: Type 'undefined' is not assignable to type 'string'.
!!! error TS2322: Type 'undefined' is not assignable to type 'string'.
};


2 changes: 1 addition & 1 deletion tests/baselines/reference/noUncheckedIndexedAccess.types
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ const fn3 = <Key extends keyof typeof myRecord2>(key: Key) => {

const v: string = myRecord2[key]; // Should error
>v : string
>myRecord2[key] : string | undefined
>myRecord2[key] : undefined
>myRecord2 : { [key: string]: string; a: string; b: string; }
>key : Key

Expand Down
20 changes: 20 additions & 0 deletions tests/cases/compiler/narrowingByNonLiteralIndexedAccess.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// @strict: true

interface IEye {
visibility: number | undefined
}

interface IPirate {
hands: number | undefined,
eyes: IEye[]
}

const pirates: IPirate[] = [];

const index: number = 1;

pirates[index].hands++;
if (pirates[index].hands) pirates[index].hands++;

pirates[index].eyes[index].visibility++;
if (pirates[index].eyes[index].visibility) pirates[index].eyes[index].visibility++;

0 comments on commit 44a8d67

Please sign in to comment.