Skip to content

Commit

Permalink
Allow type narrowed by multi property access for discriminant/typeof/…
Browse files Browse the repository at this point in the history
…truthiness

add tests

update tests

fix

remove useless code

fix test reference
  • Loading branch information
ShuiRuTian committed Nov 18, 2021
1 parent a75f26e commit 40521d7
Show file tree
Hide file tree
Showing 56 changed files with 8,357 additions and 247 deletions.
483 changes: 403 additions & 80 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

7 changes: 2 additions & 5 deletions tests/baselines/reference/controlFlowOptionalChain.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,10 @@ tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(463,9): error TS
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(498,13): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(501,13): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(515,13): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(518,13): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(567,21): error TS2532: Object is possibly 'undefined'.


==== tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts (61 errors) ====
==== tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts (60 errors) ====
// assignments in shortcutting chain
declare const o: undefined | {
[key: string]: any;
Expand Down Expand Up @@ -697,9 +696,7 @@ tests/cases/conformance/controlFlow/controlFlowOptionalChain.ts(567,21): error T
!!! error TS2532: Object is possibly 'undefined'.
break;
default:
o.foo; // Error
~
!!! error TS2532: Object is possibly 'undefined'.
o.foo;
break;
}
}
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/controlFlowOptionalChain.js
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ function f41(o: Thing | undefined) {
o.foo; // Error
break;
default:
o.foo; // Error
o.foo;
break;
}
}
Expand Down Expand Up @@ -1049,7 +1049,7 @@ function f41(o) {
o.foo; // Error
break;
default:
o.foo; // Error
o.foo;
break;
}
}
Expand Down
12 changes: 1 addition & 11 deletions tests/baselines/reference/controlFlowOptionalChain.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -1438,9 +1438,7 @@ function f23(o: Thing | undefined) {
>foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14))

o.foo; // Error
>o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14))
>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 439, 13))
>foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14))
}
else {
o.foo;
Expand All @@ -1460,19 +1458,15 @@ function f23(o: Thing | undefined) {
}
else {
o.foo; // Error
>o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14))
>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 439, 13))
>foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14))
}
if (typeof o?.foo == "undefined") {
>o?.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14))
>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 439, 13))
>foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14))

o.foo; // Error
>o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14))
>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 439, 13))
>foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14))
}
else {
o.foo;
Expand All @@ -1492,9 +1486,7 @@ function f23(o: Thing | undefined) {
}
else {
o.foo; // Error
>o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14))
>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 439, 13))
>foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14))
}
}

Expand Down Expand Up @@ -1636,13 +1628,11 @@ function f41(o: Thing | undefined) {
break;
case "undefined":
o.foo; // Error
>o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14))
>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 505, 13))
>foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14))

break;
default:
o.foo; // Error
o.foo;
>o.foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14))
>o : Symbol(o, Decl(controlFlowOptionalChain.ts, 505, 13))
>foo : Symbol(foo, Decl(controlFlowOptionalChain.ts, 161, 14))
Expand Down
34 changes: 17 additions & 17 deletions tests/baselines/reference/controlFlowOptionalChain.types
Original file line number Diff line number Diff line change
Expand Up @@ -1618,9 +1618,9 @@ function f23(o: Thing | undefined) {
>"undefined" : "undefined"

o.foo; // Error
>o.foo : never
>o : Thing | undefined
>foo : never
>o.foo : any
>o : undefined
>foo : any
}
else {
o.foo;
Expand All @@ -1643,9 +1643,9 @@ function f23(o: Thing | undefined) {
}
else {
o.foo; // Error
>o.foo : never
>o : Thing | undefined
>foo : never
>o.foo : any
>o : undefined
>foo : any
}
if (typeof o?.foo == "undefined") {
>typeof o?.foo == "undefined" : boolean
Expand All @@ -1656,9 +1656,9 @@ function f23(o: Thing | undefined) {
>"undefined" : "undefined"

o.foo; // Error
>o.foo : never
>o : Thing | undefined
>foo : never
>o.foo : any
>o : undefined
>foo : any
}
else {
o.foo;
Expand All @@ -1681,9 +1681,9 @@ function f23(o: Thing | undefined) {
}
else {
o.foo; // Error
>o.foo : never
>o : Thing | undefined
>foo : never
>o.foo : any
>o : undefined
>foo : any
}
}

Expand Down Expand Up @@ -1852,15 +1852,15 @@ function f41(o: Thing | undefined) {
>"undefined" : "undefined"

o.foo; // Error
>o.foo : never
>o : Thing | undefined
>foo : never
>o.foo : any
>o : undefined
>foo : any

break;
default:
o.foo; // Error
o.foo;
>o.foo : never
>o : Thing | undefined
>o : Thing
>foo : never

break;
Expand Down
16 changes: 8 additions & 8 deletions tests/baselines/reference/destructuringControlFlow.types
Original file line number Diff line number Diff line change
Expand Up @@ -63,34 +63,34 @@ function f2(obj: [number, string] | null[]) {
>obj[0] : number | null
>obj : [number, string] | null[]
>0 : 0
>obj[1] : string | null
>obj : [number, string] | null[]
>obj[1] : string
>obj : [number, string]
>1 : 1

let c0 = obj[0]; // number
>c0 : number
>obj[0] : number
>obj : [number, string] | null[]
>obj : [number, string]
>0 : 0

let c1 = obj[1]; // string
>c1 : string
>obj[1] : string
>obj : [number, string] | null[]
>obj : [number, string]
>1 : 1

let [d0, d1] = obj;
>d0 : number
>d1 : string
>obj : [number, string] | null[]
>obj : [number, string]

([c0, c1] = obj);
>([c0, c1] = obj) : [number, string] | null[]
>[c0, c1] = obj : [number, string] | null[]
>([c0, c1] = obj) : [number, string]
>[c0, c1] = obj : [number, string]
>[c0, c1] : [number, string]
>c0 : number
>c1 : string
>obj : [number, string] | null[]
>obj : [number, string]
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,5 +86,5 @@ function foo2(x: A | B): any {
>x : B
}
x; // never
>x : never
>x : B
}
7 changes: 5 additions & 2 deletions tests/baselines/reference/discriminatedUnionTypes2.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ tests/cases/conformance/types/union/discriminatedUnionTypes2.ts(27,30): error TS
Object literal may only specify known properties, and 'c' does not exist in type '{ a: null; b: string; }'.
tests/cases/conformance/types/union/discriminatedUnionTypes2.ts(32,11): error TS2339: Property 'b' does not exist on type '{ a: 0; b: string; } | { a: T; c: number; }'.
Property 'b' does not exist on type '{ a: T; c: number; }'.
tests/cases/conformance/types/union/discriminatedUnionTypes2.ts(132,11): error TS2339: Property 'value' does not exist on type 'never'.


==== tests/cases/conformance/types/union/discriminatedUnionTypes2.ts (2 errors) ====
==== tests/cases/conformance/types/union/discriminatedUnionTypes2.ts (3 errors) ====
function f10(x : { kind: false, a: string } | { kind: true, b: string } | { kind: string, c: string }) {
if (x.kind === false) {
x.a;
Expand Down Expand Up @@ -142,7 +143,9 @@ tests/cases/conformance/types/union/discriminatedUnionTypes2.ts(32,11): error TS
x.value; // number
}
else {
x.value; // number
x.value; // Error, x is never
~~~~~
!!! error TS2339: Property 'value' does not exist on type 'never'.
}
}

Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/discriminatedUnionTypes2.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ function foo1(x: RuntimeValue & { type: 'number' }) {
x.value; // number
}
else {
x.value; // number
x.value; // Error, x is never
}
}

Expand Down Expand Up @@ -226,7 +226,7 @@ function foo1(x) {
x.value; // number
}
else {
x.value; // number
x.value; // Error, x is never
}
}
function foo2(x) {
Expand Down
4 changes: 1 addition & 3 deletions tests/baselines/reference/discriminatedUnionTypes2.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -366,10 +366,8 @@ function foo1(x: RuntimeValue & { type: 'number' }) {
>value : Symbol(value, Decl(discriminatedUnionTypes2.ts, 122, 23))
}
else {
x.value; // number
>x.value : Symbol(value, Decl(discriminatedUnionTypes2.ts, 122, 23))
x.value; // Error, x is never
>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 126, 14))
>value : Symbol(value, Decl(discriminatedUnionTypes2.ts, 122, 23))
}
}

Expand Down
8 changes: 4 additions & 4 deletions tests/baselines/reference/discriminatedUnionTypes2.types
Original file line number Diff line number Diff line change
Expand Up @@ -379,10 +379,10 @@ function foo1(x: RuntimeValue & { type: 'number' }) {
>value : number
}
else {
x.value; // number
>x.value : number
>x : { type: "number"; value: number; } & { type: "number"; }
>value : number
x.value; // Error, x is never
>x.value : any
>x : never
>value : any
}
}

Expand Down
91 changes: 91 additions & 0 deletions tests/baselines/reference/discriminatedUnionTypes3.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
tests/cases/conformance/types/union/discriminatedUnionTypes3.ts(59,11): error TS2339: Property 's' does not exist on type 'T'.
tests/cases/conformance/types/union/discriminatedUnionTypes3.ts(78,10): error TS2339: Property 'property' does not exist on type 'SomeReturnType'.
Property 'property' does not exist on type 'Err'.


==== tests/cases/conformance/types/union/discriminatedUnionTypes3.ts (2 errors) ====
type A = { type2: "a", a: number }
type B = { type2: "b", b: number }
type C = { type2: "c", b: number | string }

type X = { type1: A, x: string }
type Y = { type1: B, y: string }
type Z = { type1: C, z: string }
type W = { type1: undefined }

function f32(x: X | Y) {
switch (x.type1.type2) {
case "a":
x.x // typeof x is X
break;
case "b":
x.y // typeof x is Y
break;
}
}

function f33(x: A | B) {
switch (x.type2) {
case "a":
x // typeof x is X
break;
case "b":
x // typeof x is Y
break;
}
}

function f34(x: X | Y) {
if (x.type1.type2 === "a") {
x.x // typeof x is X
} else if (x.type1.type2 === "b") {
x.y // typeof x is Y
}
}

function f35(x: X | W) {
if (x.type1?.type2 === "a") {
x.x
}
}

function f36(x: X | W) {
x.type1?.type2 ?? x;
}

type S = { sub: { type0: X }, s: string }
type T = { sub: { type0: Y }, t: string }

function f37(s: S | T) {
if (s.sub.type0.type1.type2 === "a") {
s.s // typeof s is S
s.sub.type0.x // type of s.sub.type is X
s.sub.type0.type1.a // type of s.sub.type.type is A
} else {
s.s // type error!
~
!!! error TS2339: Property 's' does not exist on type 'T'.
}
}

// Repro from #44435

type Correct = {
code: string
property: true
err: undefined
}
type Err = {
err: `${string} is wrong!`
}
type SomeReturnType = Correct | Err;

const example: SomeReturnType = {} as SomeReturnType;

if (example.err === undefined) {
example.property; // true
~~~~~~~~
!!! error TS2339: Property 'property' does not exist on type 'SomeReturnType'.
!!! error TS2339: Property 'property' does not exist on type 'Err'.
}

Loading

0 comments on commit 40521d7

Please sign in to comment.