Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion tsc/internal/checker/flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -1060,7 +1060,8 @@ func (c *Checker) getTypeAtSwitchClause(f *FlowState, flow *ast.FlowNode) FlowTy
data := flow.Node.AsFlowSwitchClauseData()
expr := ast.SkipParentheses(data.SwitchStatement.Expression())
flowType := c.getTypeAtFlowNode(f, flow.Antecedent)
t := flowType.t
nonEvolvingType := c.finalizeEvolvingArrayType(flowType.t)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this just matches the preestablished pattern used by other narrowing~ functions like getTypeAtFlowCondition, getTypeAtFlowCall and co.

t := nonEvolvingType
switch {
case c.isMatchingReference(f.reference, expr):
t = c.narrowTypeBySwitchOnDiscriminant(t, data)
Expand All @@ -1085,6 +1086,9 @@ func (c *Checker) getTypeAtSwitchClause(f *FlowState, flow *ast.FlowNode) FlowTy
t = c.narrowTypeBySwitchOnDiscriminantProperty(t, access, data)
}
}
if t == nonEvolvingType {
return flowType
}
return c.newFlowType(t, flowType.incomplete)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
narrowSwitchOnEvolvingArrayNoCrash1.ts(2,9): error TS7034: Variable 'a' implicitly has type 'any[]' in some locations where its type cannot be determined.
narrowSwitchOnEvolvingArrayNoCrash1.ts(3,24): error TS7005: Variable 'a' implicitly has an 'any[]' type.
narrowSwitchOnEvolvingArrayNoCrash1.ts(3,34): error TS2678: Type 'number' is not comparable to type 'any[]'.
narrowSwitchOnEvolvingArrayNoCrash1.ts(7,9): error TS7034: Variable 'b' implicitly has type 'any[]' in some locations where its type cannot be determined.
narrowSwitchOnEvolvingArrayNoCrash1.ts(8,11): error TS7005: Variable 'b' implicitly has an 'any[]' type.
narrowSwitchOnEvolvingArrayNoCrash1.ts(9,10): error TS2678: Type 'number' is not comparable to type 'any[]'.
narrowSwitchOnEvolvingArrayNoCrash1.ts(15,9): error TS7034: Variable 'b' implicitly has type 'any[]' in some locations where its type cannot be determined.
narrowSwitchOnEvolvingArrayNoCrash1.ts(16,7): error TS7005: Variable 'b' implicitly has an 'any[]' type.
narrowSwitchOnEvolvingArrayNoCrash1.ts(16,7): error TS2367: This comparison appears to be unintentional because the types 'any[]' and 'number' have no overlap.
narrowSwitchOnEvolvingArrayNoCrash1.ts(22,7): error TS7034: Variable 'c' implicitly has type 'any[]' in some locations where its type cannot be determined.
narrowSwitchOnEvolvingArrayNoCrash1.ts(23,18): error TS7005: Variable 'c' implicitly has an 'any[]' type.
narrowSwitchOnEvolvingArrayNoCrash1.ts(26,13): error TS2322: Type 'string[]' is not assignable to type 'number[]'.
Type 'string' is not assignable to type 'number'.
narrowSwitchOnEvolvingArrayNoCrash1.ts(32,7): error TS7034: Variable 'c' implicitly has type 'any[]' in some locations where its type cannot be determined.
narrowSwitchOnEvolvingArrayNoCrash1.ts(33,14): error TS7005: Variable 'c' implicitly has an 'any[]' type.
narrowSwitchOnEvolvingArrayNoCrash1.ts(35,11): error TS2322: Type 'string[]' is not assignable to type 'number[]'.
Type 'string' is not assignable to type 'number'.


==== narrowSwitchOnEvolvingArrayNoCrash1.ts (15 errors) ====
function f1() {
const a = [];
~
!!! error TS7034: Variable 'a' implicitly has type 'any[]' in some locations where its type cannot be determined.
while (true) switch (a) { case 0: }
~
!!! error TS7005: Variable 'a' implicitly has an 'any[]' type.
~
!!! error TS2678: Type 'number' is not comparable to type 'any[]'.
}

function f2() {
const b = [];
~
!!! error TS7034: Variable 'b' implicitly has type 'any[]' in some locations where its type cannot be determined.
switch (b) {
~
!!! error TS7005: Variable 'b' implicitly has an 'any[]' type.
case 0:
~
!!! error TS2678: Type 'number' is not comparable to type 'any[]'.
b;
}
}

function f3() {
const b = [];
~
!!! error TS7034: Variable 'b' implicitly has type 'any[]' in some locations where its type cannot be determined.
if (b === 0) {
~
!!! error TS7005: Variable 'b' implicitly has an 'any[]' type.
~~~~~~~
!!! error TS2367: This comparison appears to be unintentional because the types 'any[]' and 'number' have no overlap.
b;
}
}

function f4() {
let c = [];
~
!!! error TS7034: Variable 'c' implicitly has type 'any[]' in some locations where its type cannot be determined.
switch (typeof c) {
~
!!! error TS7005: Variable 'c' implicitly has an 'any[]' type.
case "object": {
c.push("x");
const arr: number[] = c;
~~~
!!! error TS2322: Type 'string[]' is not assignable to type 'number[]'.
!!! error TS2322: Type 'string' is not assignable to type 'number'.
}
}
}

function f5() {
let c = [];
~
!!! error TS7034: Variable 'c' implicitly has type 'any[]' in some locations where its type cannot be determined.
if (typeof c === "object") {
~
!!! error TS7005: Variable 'c' implicitly has an 'any[]' type.
c.push("x");
const arr: number[] = c;
~~~
!!! error TS2322: Type 'string[]' is not assignable to type 'number[]'.
!!! error TS2322: Type 'string' is not assignable to type 'number'.
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//// [tests/cases/compiler/narrowSwitchOnEvolvingArrayNoCrash1.ts] ////

=== narrowSwitchOnEvolvingArrayNoCrash1.ts ===
function f1() {
>f1 : Symbol(f1, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 0, 0))

const a = [];
>a : Symbol(a, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 1, 7))

while (true) switch (a) { case 0: }
>a : Symbol(a, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 1, 7))
}

function f2() {
>f2 : Symbol(f2, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 3, 1))

const b = [];
>b : Symbol(b, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 6, 7))

switch (b) {
>b : Symbol(b, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 6, 7))

case 0:
b;
>b : Symbol(b, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 6, 7))
}
}

function f3() {
>f3 : Symbol(f3, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 11, 1))

const b = [];
>b : Symbol(b, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 14, 7))

if (b === 0) {
>b : Symbol(b, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 14, 7))

b;
>b : Symbol(b, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 14, 7))
}
}

function f4() {
>f4 : Symbol(f4, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 18, 1))

let c = [];
>c : Symbol(c, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 21, 5))

switch (typeof c) {
>c : Symbol(c, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 21, 5))

case "object": {
c.push("x");
>c.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
>c : Symbol(c, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 21, 5))
>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))

const arr: number[] = c;
>arr : Symbol(arr, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 25, 11))
>c : Symbol(c, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 21, 5))
}
}
}

function f5() {
>f5 : Symbol(f5, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 28, 1))

let c = [];
>c : Symbol(c, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 31, 5))

if (typeof c === "object") {
>c : Symbol(c, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 31, 5))

c.push("x");
>c.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
>c : Symbol(c, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 31, 5))
>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))

const arr: number[] = c;
>arr : Symbol(arr, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 34, 9))
>c : Symbol(c, Decl(narrowSwitchOnEvolvingArrayNoCrash1.ts, 31, 5))
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
//// [tests/cases/compiler/narrowSwitchOnEvolvingArrayNoCrash1.ts] ////

=== narrowSwitchOnEvolvingArrayNoCrash1.ts ===
function f1() {
>f1 : () => void

const a = [];
>a : any[]
>[] : never[]

while (true) switch (a) { case 0: }
>true : true
>a : any[]
>0 : 0
}

function f2() {
>f2 : () => void

const b = [];
>b : any[]
>[] : never[]

switch (b) {
>b : any[]

case 0:
>0 : 0

b;
>b : never
}
}

function f3() {
>f3 : () => void

const b = [];
>b : any[]
>[] : never[]

if (b === 0) {
>b === 0 : boolean
>b : any[]
>0 : 0

b;
>b : never
}
}

function f4() {
>f4 : () => void

let c = [];
>c : any[]
>[] : never[]

switch (typeof c) {
>typeof c : "bigint" | "boolean" | "function" | "number" | "object" | "string" | "symbol" | "undefined"
>c : any[]

case "object": {
>"object" : "object"

c.push("x");
>c.push("x") : number
>c.push : (...items: any[]) => number
>c : any[]
>push : (...items: any[]) => number
>"x" : "x"

const arr: number[] = c;
>arr : number[]
>c : string[]
}
}
}

function f5() {
>f5 : () => void

let c = [];
>c : any[]
>[] : never[]

if (typeof c === "object") {
>typeof c === "object" : boolean
>typeof c : "bigint" | "boolean" | "function" | "number" | "object" | "string" | "symbol" | "undefined"
>c : any[]
>"object" : "object"

c.push("x");
>c.push("x") : number
>c.push : (...items: any[]) => number
>c : any[]
>push : (...items: any[]) => number
>"x" : "x"

const arr: number[] = c;
>arr : number[]
>c : string[]
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// @target: es2015
// @strict: true
// @noEmit: true

function f1() {
const a = [];
while (true) switch (a) { case 0: }
}

function f2() {
const b = [];
switch (b) {
case 0:
b;
}
}

function f3() {
const b = [];
if (b === 0) {
b;
}
}

function f4() {
let c = [];
switch (typeof c) {
case "object": {
c.push("x");
const arr: number[] = c;
}
}
}

function f5() {
let c = [];
if (typeof c === "object") {
c.push("x");
const arr: number[] = c;
}
}