Skip to content

Commit ba7033b

Browse files
committed
Disallow more flavors of property accesses on never in expression space
1 parent efc9c06 commit ba7033b

15 files changed

+361
-4
lines changed

src/compiler/checker.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10863,7 +10863,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1086310863
mapType(baseConstraint, t => sliceTupleType(t as TupleTypeReference, index)) :
1086410864
createArrayType(elementType);
1086510865
}
10866-
else if (isArrayLikeType(parentType)) {
10866+
else if (isArrayLikeType(parentType) && !isErrorType(elementType)) {
1086710867
const indexType = getNumberLiteralType(index);
1086810868
const accessFlags = AccessFlags.ExpressionPosition | (noTupleBoundsCheck || hasDefaultValue(declaration) ? AccessFlags.NoTupleBoundsCheck : 0);
1086910869
const declaredType = getIndexedAccessTypeOrUndefined(parentType, indexType, accessFlags, declaration.name) || errorType;
@@ -18040,7 +18040,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1804018040
}
1804118041
}
1804218042
if (!(indexType.flags & TypeFlags.Nullable) && isTypeAssignableToKind(indexType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike)) {
18043-
if (objectType.flags & (TypeFlags.Any | TypeFlags.Never)) {
18043+
if (objectType.flags & TypeFlags.Any || objectType.flags & TypeFlags.Never && !(accessFlags & AccessFlags.ExpressionPosition)) {
1804418044
return objectType;
1804518045
}
1804618046
// If no index signature is applicable, we default to the string index signature. In effect, this means the string
@@ -42893,7 +42893,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4289342893
const allowAsyncIterables = (use & IterationUse.AllowsAsyncIterablesFlag) !== 0;
4289442894
if (inputType === neverType) {
4289542895
reportTypeNotIterableError(errorNode!, inputType, allowAsyncIterables); // TODO: GH#18217
42896-
return undefined;
42896+
return errorType;
4289742897
}
4289842898

4289942899
const uplevelIteration = languageVersion >= ScriptTarget.ES2015;

tests/baselines/reference/arrayDestructuringInSwitch2.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ function foo(x: X): 1 {
3636

3737
default:
3838
const [n] = a;
39-
>n : never
39+
>n : any
4040
>a : never
4141

4242
return a;
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
controlFlowAssignmentPatternOrder.ts(6,9): error TS2339: Property '1' does not exist on type 'never'.
2+
controlFlowAssignmentPatternOrder.ts(12,9): error TS2339: Property '0' does not exist on type 'never'.
3+
controlFlowAssignmentPatternOrder.ts(31,9): error TS2339: Property '1' does not exist on type 'never'.
4+
controlFlowAssignmentPatternOrder.ts(37,9): error TS2339: Property '0' does not exist on type 'never'.
5+
controlFlowAssignmentPatternOrder.ts(56,14): error TS2339: Property '1' does not exist on type 'never'.
6+
controlFlowAssignmentPatternOrder.ts(62,14): error TS2339: Property '0' does not exist on type 'never'.
7+
8+
9+
==== controlFlowAssignmentPatternOrder.ts (6 errors) ====
10+
// https://github.com/microsoft/TypeScript/pull/41094#issuecomment-716044363
11+
declare function f(): void;
12+
{
13+
let a: 0 | 1 = 0;
14+
let b: 0 | 1 | 9;
15+
[{ [(a = 1)]: b } = [9, a] as const] = [];
16+
~~~~~~~
17+
!!! error TS2339: Property '1' does not exist on type 'never'.
18+
const bb: 0 = b;
19+
}
20+
{
21+
let a: 0 | 1 = 1;
22+
let b: 0 | 1 | 9;
23+
[{ [a]: b } = [9, a = 0] as const] = [];
24+
~
25+
!!! error TS2339: Property '0' does not exist on type 'never'.
26+
const bb: 9 = b;
27+
}
28+
{
29+
let a: 0 | 1 = 0;
30+
let b: 0 | 1 | 8 | 9;
31+
[{ [(a = 1)]: b } = [9, a] as const] = [[9, 8] as const];
32+
const bb: 0 | 8 = b;
33+
}
34+
{
35+
let a: 0 | 1 = 1;
36+
let b: 0 | 1 | 8 | 9;
37+
[{ [a]: b } = [a = 0, 9] as const] = [[8, 9] as const];
38+
const bb: 0 | 8 = b;
39+
}
40+
// same as above but on left of a binary expression
41+
{
42+
let a: 0 | 1 = 0;
43+
let b: 0 | 1 | 9;
44+
[{ [(a = 1)]: b } = [9, a] as const] = [], f();
45+
~~~~~~~
46+
!!! error TS2339: Property '1' does not exist on type 'never'.
47+
const bb: 0 = b;
48+
}
49+
{
50+
let a: 0 | 1 = 1;
51+
let b: 0 | 1 | 9;
52+
[{ [a]: b } = [9, a = 0] as const] = [], f();
53+
~
54+
!!! error TS2339: Property '0' does not exist on type 'never'.
55+
const bb: 9 = b;
56+
}
57+
{
58+
let a: 0 | 1 = 0;
59+
let b: 0 | 1 | 8 | 9;
60+
[{ [(a = 1)]: b } = [9, a] as const] = [[9, 8] as const], f();
61+
const bb: 0 | 8 = b;
62+
}
63+
{
64+
let a: 0 | 1 = 1;
65+
let b: 0 | 1 | 8 | 9;
66+
[{ [a]: b } = [a = 0, 9] as const] = [[8, 9] as const], f();
67+
const bb: 0 | 8 = b;
68+
}
69+
// same as above but on right of a binary expression
70+
{
71+
let a: 0 | 1 = 0;
72+
let b: 0 | 1 | 9;
73+
f(), [{ [(a = 1)]: b } = [9, a] as const] = [];
74+
~~~~~~~
75+
!!! error TS2339: Property '1' does not exist on type 'never'.
76+
const bb: 0 = b;
77+
}
78+
{
79+
let a: 0 | 1 = 1;
80+
let b: 0 | 1 | 9;
81+
f(), [{ [a]: b } = [9, a = 0] as const] = [];
82+
~
83+
!!! error TS2339: Property '0' does not exist on type 'never'.
84+
const bb: 9 = b;
85+
}
86+
{
87+
let a: 0 | 1 = 0;
88+
let b: 0 | 1 | 8 | 9;
89+
f(), [{ [(a = 1)]: b } = [9, a] as const] = [[9, 8] as const];
90+
const bb: 0 | 8 = b;
91+
}
92+
{
93+
let a: 0 | 1 = 1;
94+
let b: 0 | 1 | 8 | 9;
95+
f(), [{ [a]: b } = [a = 0, 9] as const] = [[8, 9] as const];
96+
const bb: 0 | 8 = b;
97+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
objectDestructuringInSwitch1.ts(11,15): error TS2339: Property 'prop' does not exist on type 'never'.
2+
3+
4+
==== objectDestructuringInSwitch1.ts (1 errors) ====
5+
type X = { kind: "a", a: { prop: 1 } } | { kind: "b", a: {} }
6+
7+
function foo(x: X): 1 {
8+
const { kind, a } = x;
9+
switch (kind) {
10+
case "a":
11+
return a.prop;
12+
case "b":
13+
return 1;
14+
default:
15+
const { prop } = a;
16+
~~~~
17+
!!! error TS2339: Property 'prop' does not exist on type 'never'.
18+
return a;
19+
}
20+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//// [tests/cases/compiler/objectDestructuringInSwitch1.ts] ////
2+
3+
=== objectDestructuringInSwitch1.ts ===
4+
type X = { kind: "a", a: { prop: 1 } } | { kind: "b", a: {} }
5+
>X : Symbol(X, Decl(objectDestructuringInSwitch1.ts, 0, 0))
6+
>kind : Symbol(kind, Decl(objectDestructuringInSwitch1.ts, 0, 10))
7+
>a : Symbol(a, Decl(objectDestructuringInSwitch1.ts, 0, 21))
8+
>prop : Symbol(prop, Decl(objectDestructuringInSwitch1.ts, 0, 26))
9+
>kind : Symbol(kind, Decl(objectDestructuringInSwitch1.ts, 0, 42))
10+
>a : Symbol(a, Decl(objectDestructuringInSwitch1.ts, 0, 53))
11+
12+
function foo(x: X): 1 {
13+
>foo : Symbol(foo, Decl(objectDestructuringInSwitch1.ts, 0, 61))
14+
>x : Symbol(x, Decl(objectDestructuringInSwitch1.ts, 2, 13))
15+
>X : Symbol(X, Decl(objectDestructuringInSwitch1.ts, 0, 0))
16+
17+
const { kind, a } = x;
18+
>kind : Symbol(kind, Decl(objectDestructuringInSwitch1.ts, 3, 9))
19+
>a : Symbol(a, Decl(objectDestructuringInSwitch1.ts, 3, 15))
20+
>x : Symbol(x, Decl(objectDestructuringInSwitch1.ts, 2, 13))
21+
22+
switch (kind) {
23+
>kind : Symbol(kind, Decl(objectDestructuringInSwitch1.ts, 3, 9))
24+
25+
case "a":
26+
return a.prop;
27+
>a.prop : Symbol(prop, Decl(objectDestructuringInSwitch1.ts, 0, 26))
28+
>a : Symbol(a, Decl(objectDestructuringInSwitch1.ts, 3, 15))
29+
>prop : Symbol(prop, Decl(objectDestructuringInSwitch1.ts, 0, 26))
30+
31+
case "b":
32+
return 1;
33+
default:
34+
const { prop } = a;
35+
>prop : Symbol(prop, Decl(objectDestructuringInSwitch1.ts, 10, 13))
36+
>a : Symbol(a, Decl(objectDestructuringInSwitch1.ts, 3, 15))
37+
38+
return a;
39+
>a : Symbol(a, Decl(objectDestructuringInSwitch1.ts, 3, 15))
40+
}
41+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//// [tests/cases/compiler/objectDestructuringInSwitch1.ts] ////
2+
3+
=== objectDestructuringInSwitch1.ts ===
4+
type X = { kind: "a", a: { prop: 1 } } | { kind: "b", a: {} }
5+
>X : { kind: "a"; a: { prop: 1;}; } | { kind: "b"; a: {}; }
6+
>kind : "a"
7+
>a : { prop: 1; }
8+
>prop : 1
9+
>kind : "b"
10+
>a : {}
11+
12+
function foo(x: X): 1 {
13+
>foo : (x: X) => 1
14+
>x : X
15+
16+
const { kind, a } = x;
17+
>kind : "a" | "b"
18+
>a : {} | { prop: 1; }
19+
>x : X
20+
21+
switch (kind) {
22+
>kind : "a" | "b"
23+
24+
case "a":
25+
>"a" : "a"
26+
27+
return a.prop;
28+
>a.prop : 1
29+
>a : { prop: 1; }
30+
>prop : 1
31+
32+
case "b":
33+
>"b" : "b"
34+
35+
return 1;
36+
>1 : 1
37+
38+
default:
39+
const { prop } = a;
40+
>prop : any
41+
>a : never
42+
43+
return a;
44+
>a : never
45+
}
46+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
parameterBindingPatternWithNever1.ts(5,29): error TS2339: Property 'foo' does not exist on type 'never'.
2+
3+
4+
==== parameterBindingPatternWithNever1.ts (1 errors) ====
5+
function something(foo: string) {}
6+
7+
type ComplexTypeThatReturnsNever = never;
8+
9+
function somethingWrapper({ foo }: ComplexTypeThatReturnsNever) {
10+
~~~
11+
!!! error TS2339: Property 'foo' does not exist on type 'never'.
12+
something(foo);
13+
}
14+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//// [tests/cases/compiler/parameterBindingPatternWithNever1.ts] ////
2+
3+
=== parameterBindingPatternWithNever1.ts ===
4+
function something(foo: string) {}
5+
>something : Symbol(something, Decl(parameterBindingPatternWithNever1.ts, 0, 0))
6+
>foo : Symbol(foo, Decl(parameterBindingPatternWithNever1.ts, 0, 19))
7+
8+
type ComplexTypeThatReturnsNever = never;
9+
>ComplexTypeThatReturnsNever : Symbol(ComplexTypeThatReturnsNever, Decl(parameterBindingPatternWithNever1.ts, 0, 34))
10+
11+
function somethingWrapper({ foo }: ComplexTypeThatReturnsNever) {
12+
>somethingWrapper : Symbol(somethingWrapper, Decl(parameterBindingPatternWithNever1.ts, 2, 41))
13+
>foo : Symbol(foo, Decl(parameterBindingPatternWithNever1.ts, 4, 27))
14+
>ComplexTypeThatReturnsNever : Symbol(ComplexTypeThatReturnsNever, Decl(parameterBindingPatternWithNever1.ts, 0, 34))
15+
16+
something(foo);
17+
>something : Symbol(something, Decl(parameterBindingPatternWithNever1.ts, 0, 0))
18+
>foo : Symbol(foo, Decl(parameterBindingPatternWithNever1.ts, 4, 27))
19+
}
20+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//// [tests/cases/compiler/parameterBindingPatternWithNever1.ts] ////
2+
3+
=== parameterBindingPatternWithNever1.ts ===
4+
function something(foo: string) {}
5+
>something : (foo: string) => void
6+
>foo : string
7+
8+
type ComplexTypeThatReturnsNever = never;
9+
>ComplexTypeThatReturnsNever : never
10+
11+
function somethingWrapper({ foo }: ComplexTypeThatReturnsNever) {
12+
>somethingWrapper : ({ foo }: ComplexTypeThatReturnsNever) => void
13+
>foo : any
14+
15+
something(foo);
16+
>something(foo) : void
17+
>something : (foo: string) => void
18+
>foo : any
19+
}
20+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
propertyAccessOnNever1.ts(5,9): error TS2339: Property 'foo' does not exist on type 'never'.
2+
propertyAccessOnNever1.ts(6,1): error TS7053: Element implicitly has an 'any' type because expression of type '"foo"' can't be used to index type 'never'.
3+
Property 'foo' does not exist on type 'never'.
4+
propertyAccessOnNever1.ts(7,9): error TS2339: Property 'foo' does not exist on type 'never'.
5+
6+
7+
==== propertyAccessOnNever1.ts (3 errors) ====
8+
// https://github.com/microsoft/TypeScript/issues/56778
9+
10+
declare const example: never;
11+
12+
example.foo;
13+
~~~
14+
!!! error TS2339: Property 'foo' does not exist on type 'never'.
15+
example['foo'];
16+
~~~~~~~~~~~~~~
17+
!!! error TS7053: Element implicitly has an 'any' type because expression of type '"foo"' can't be used to index type 'never'.
18+
!!! error TS7053: Property 'foo' does not exist on type 'never'.
19+
const { foo } = example
20+
~~~
21+
!!! error TS2339: Property 'foo' does not exist on type 'never'.
22+

0 commit comments

Comments
 (0)