Skip to content

Commit 669acb4

Browse files
Revert "Revert "Add check for delete expression must be optional (#37921)" (#38154)"
This reverts commit 1b8c68d.
1 parent 1b8c68d commit 669acb4

14 files changed

+856
-4
lines changed

src/compiler/checker.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27682,12 +27682,23 @@ namespace ts {
2768227682
}
2768327683
const links = getNodeLinks(expr);
2768427684
const symbol = getExportSymbolOfValueSymbolIfExported(links.resolvedSymbol);
27685-
if (symbol && isReadonlySymbol(symbol)) {
27686-
error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_read_only_property);
27685+
if (symbol) {
27686+
if (isReadonlySymbol(symbol)) {
27687+
error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_read_only_property);
27688+
}
27689+
27690+
checkDeleteExpressionMustBeOptional(expr, getTypeOfSymbol(symbol));
2768727691
}
2768827692
return booleanType;
2768927693
}
2769027694

27695+
function checkDeleteExpressionMustBeOptional(expr: AccessExpression, type: Type) {
27696+
const AnyOrUnknownOrNeverFlags = TypeFlags.AnyOrUnknown | TypeFlags.Never;
27697+
if (strictNullChecks && !(type.flags & AnyOrUnknownOrNeverFlags) && !(getFalsyFlags(type) & TypeFlags.Undefined)) {
27698+
error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_optional);
27699+
}
27700+
}
27701+
2769127702
function checkTypeOfExpression(node: TypeOfExpression): Type {
2769227703
checkExpression(node.expression);
2769327704
return typeofType;

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2963,6 +2963,10 @@
29632963
"category": "Error",
29642964
"code": 2789
29652965
},
2966+
"The operand of a 'delete' operator must be optional.": {
2967+
"category": "Error",
2968+
"code": 2790
2969+
},
29662970

29672971
"Import declaration '{0}' is using private name '{1}'.": {
29682972
"category": "Error",

tests/baselines/reference/controlFlowDeleteOperator.errors.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts(10,12): error TS2790: The operand of a 'delete' operator must be optional.
12
tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts(14,12): error TS2703: The operand of a 'delete' operator must be a property reference.
23

34

4-
==== tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts (1 errors) ====
5+
==== tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts (2 errors) ====
56
function f() {
67
let x: { a?: number | string, b: number | string } = { b: 1 };
78
x.a;
@@ -12,6 +13,8 @@ tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts(14,12): error T
1213
x.b;
1314
delete x.a;
1415
delete x.b;
16+
~~~
17+
!!! error TS2790: The operand of a 'delete' operator must be optional.
1518
x.a;
1619
x.b;
1720
x;
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(2,8): error TS2790: The operand of a 'delete' operator must be optional.
2+
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(3,9): error TS2790: The operand of a 'delete' operator must be optional.
3+
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(6,8): error TS2790: The operand of a 'delete' operator must be optional.
4+
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(7,9): error TS2790: The operand of a 'delete' operator must be optional.
5+
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(10,8): error TS2790: The operand of a 'delete' operator must be optional.
6+
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(11,9): error TS2790: The operand of a 'delete' operator must be optional.
7+
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(14,8): error TS2790: The operand of a 'delete' operator must be optional.
8+
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(15,8): error TS2790: The operand of a 'delete' operator must be optional.
9+
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(16,9): error TS2790: The operand of a 'delete' operator must be optional.
10+
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(19,8): error TS2790: The operand of a 'delete' operator must be optional.
11+
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(20,9): error TS2790: The operand of a 'delete' operator must be optional.
12+
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(23,8): error TS2790: The operand of a 'delete' operator must be optional.
13+
tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts(24,9): error TS2790: The operand of a 'delete' operator must be optional.
14+
15+
16+
==== tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts (13 errors) ====
17+
declare const o1: undefined | { b: string };
18+
delete o1?.b;
19+
~~~~~
20+
!!! error TS2790: The operand of a 'delete' operator must be optional.
21+
delete (o1?.b);
22+
~~~~~
23+
!!! error TS2790: The operand of a 'delete' operator must be optional.
24+
25+
declare const o2: undefined | { b: { c: string } };
26+
delete o2?.b.c;
27+
~~~~~~~
28+
!!! error TS2790: The operand of a 'delete' operator must be optional.
29+
delete (o2?.b.c);
30+
~~~~~~~
31+
!!! error TS2790: The operand of a 'delete' operator must be optional.
32+
33+
declare const o3: { b: undefined | { c: string } };
34+
delete o3.b?.c;
35+
~~~~~~~
36+
!!! error TS2790: The operand of a 'delete' operator must be optional.
37+
delete (o3.b?.c);
38+
~~~~~~~
39+
!!! error TS2790: The operand of a 'delete' operator must be optional.
40+
41+
declare const o4: { b?: { c: { d?: { e: string } } } };
42+
delete o4.b?.c.d?.e;
43+
~~~~~~~~~~~~
44+
!!! error TS2790: The operand of a 'delete' operator must be optional.
45+
delete (o4.b?.c.d)?.e;
46+
~~~~~~~~~~~~~~
47+
!!! error TS2790: The operand of a 'delete' operator must be optional.
48+
delete (o4.b?.c.d?.e);
49+
~~~~~~~~~~~~
50+
!!! error TS2790: The operand of a 'delete' operator must be optional.
51+
52+
declare const o5: { b?(): { c: { d?: { e: string } } } };
53+
delete o5.b?.().c.d?.e;
54+
~~~~~~~~~~~~~~~
55+
!!! error TS2790: The operand of a 'delete' operator must be optional.
56+
delete (o5.b?.().c.d?.e);
57+
~~~~~~~~~~~~~~~
58+
!!! error TS2790: The operand of a 'delete' operator must be optional.
59+
60+
declare const o6: { b?: { c: { d?: { e: string } } } };
61+
delete o6.b?.['c'].d?.['e'];
62+
~~~~~~~~~~~~~~~~~~~~
63+
!!! error TS2790: The operand of a 'delete' operator must be optional.
64+
delete (o6.b?.['c'].d?.['e']);
65+
~~~~~~~~~~~~~~~~~~~~
66+
!!! error TS2790: The operand of a 'delete' operator must be optional.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
tests/cases/compiler/deleteExpressionMustBeOptional.ts(34,10): error TS2339: Property 'j' does not exist on type 'Foo'.
2+
3+
4+
==== tests/cases/compiler/deleteExpressionMustBeOptional.ts (1 errors) ====
5+
interface Foo {
6+
a: number
7+
b: number | undefined
8+
c: number | null
9+
d?: number
10+
e: number | undefined | null
11+
f?: number | undefined | null
12+
g: unknown
13+
h: any
14+
i: never
15+
}
16+
17+
interface AA {
18+
[s: string]: number
19+
}
20+
21+
type BB = {
22+
[P in keyof any]: number
23+
}
24+
25+
declare const f: Foo
26+
declare const a: AA
27+
declare const b: BB
28+
29+
delete f.a
30+
delete f.b
31+
delete f.c
32+
delete f.d
33+
delete f.e
34+
delete f.f
35+
delete f.g
36+
delete f.h
37+
delete f.i
38+
delete f.j
39+
~
40+
!!! error TS2339: Property 'j' does not exist on type 'Foo'.
41+
42+
delete a.a
43+
delete a.b
44+
45+
delete b.a
46+
delete b.b
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//// [deleteExpressionMustBeOptional.ts]
2+
interface Foo {
3+
a: number
4+
b: number | undefined
5+
c: number | null
6+
d?: number
7+
e: number | undefined | null
8+
f?: number | undefined | null
9+
g: unknown
10+
h: any
11+
i: never
12+
}
13+
14+
interface AA {
15+
[s: string]: number
16+
}
17+
18+
type BB = {
19+
[P in keyof any]: number
20+
}
21+
22+
declare const f: Foo
23+
declare const a: AA
24+
declare const b: BB
25+
26+
delete f.a
27+
delete f.b
28+
delete f.c
29+
delete f.d
30+
delete f.e
31+
delete f.f
32+
delete f.g
33+
delete f.h
34+
delete f.i
35+
delete f.j
36+
37+
delete a.a
38+
delete a.b
39+
40+
delete b.a
41+
delete b.b
42+
43+
//// [deleteExpressionMustBeOptional.js]
44+
delete f.a;
45+
delete f.b;
46+
delete f.c;
47+
delete f.d;
48+
delete f.e;
49+
delete f.f;
50+
delete f.g;
51+
delete f.h;
52+
delete f.i;
53+
delete f.j;
54+
delete a.a;
55+
delete a.b;
56+
delete b.a;
57+
delete b.b;
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
=== tests/cases/compiler/deleteExpressionMustBeOptional.ts ===
2+
interface Foo {
3+
>Foo : Symbol(Foo, Decl(deleteExpressionMustBeOptional.ts, 0, 0))
4+
5+
a: number
6+
>a : Symbol(Foo.a, Decl(deleteExpressionMustBeOptional.ts, 0, 15))
7+
8+
b: number | undefined
9+
>b : Symbol(Foo.b, Decl(deleteExpressionMustBeOptional.ts, 1, 13))
10+
11+
c: number | null
12+
>c : Symbol(Foo.c, Decl(deleteExpressionMustBeOptional.ts, 2, 25))
13+
14+
d?: number
15+
>d : Symbol(Foo.d, Decl(deleteExpressionMustBeOptional.ts, 3, 20))
16+
17+
e: number | undefined | null
18+
>e : Symbol(Foo.e, Decl(deleteExpressionMustBeOptional.ts, 4, 14))
19+
20+
f?: number | undefined | null
21+
>f : Symbol(Foo.f, Decl(deleteExpressionMustBeOptional.ts, 5, 32))
22+
23+
g: unknown
24+
>g : Symbol(Foo.g, Decl(deleteExpressionMustBeOptional.ts, 6, 33))
25+
26+
h: any
27+
>h : Symbol(Foo.h, Decl(deleteExpressionMustBeOptional.ts, 7, 14))
28+
29+
i: never
30+
>i : Symbol(Foo.i, Decl(deleteExpressionMustBeOptional.ts, 8, 10))
31+
}
32+
33+
interface AA {
34+
>AA : Symbol(AA, Decl(deleteExpressionMustBeOptional.ts, 10, 1))
35+
36+
[s: string]: number
37+
>s : Symbol(s, Decl(deleteExpressionMustBeOptional.ts, 13, 5))
38+
}
39+
40+
type BB = {
41+
>BB : Symbol(BB, Decl(deleteExpressionMustBeOptional.ts, 14, 1))
42+
43+
[P in keyof any]: number
44+
>P : Symbol(P, Decl(deleteExpressionMustBeOptional.ts, 17, 5))
45+
}
46+
47+
declare const f: Foo
48+
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
49+
>Foo : Symbol(Foo, Decl(deleteExpressionMustBeOptional.ts, 0, 0))
50+
51+
declare const a: AA
52+
>a : Symbol(a, Decl(deleteExpressionMustBeOptional.ts, 21, 13))
53+
>AA : Symbol(AA, Decl(deleteExpressionMustBeOptional.ts, 10, 1))
54+
55+
declare const b: BB
56+
>b : Symbol(b, Decl(deleteExpressionMustBeOptional.ts, 22, 13))
57+
>BB : Symbol(BB, Decl(deleteExpressionMustBeOptional.ts, 14, 1))
58+
59+
delete f.a
60+
>f.a : Symbol(Foo.a, Decl(deleteExpressionMustBeOptional.ts, 0, 15))
61+
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
62+
>a : Symbol(Foo.a, Decl(deleteExpressionMustBeOptional.ts, 0, 15))
63+
64+
delete f.b
65+
>f.b : Symbol(Foo.b, Decl(deleteExpressionMustBeOptional.ts, 1, 13))
66+
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
67+
>b : Symbol(Foo.b, Decl(deleteExpressionMustBeOptional.ts, 1, 13))
68+
69+
delete f.c
70+
>f.c : Symbol(Foo.c, Decl(deleteExpressionMustBeOptional.ts, 2, 25))
71+
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
72+
>c : Symbol(Foo.c, Decl(deleteExpressionMustBeOptional.ts, 2, 25))
73+
74+
delete f.d
75+
>f.d : Symbol(Foo.d, Decl(deleteExpressionMustBeOptional.ts, 3, 20))
76+
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
77+
>d : Symbol(Foo.d, Decl(deleteExpressionMustBeOptional.ts, 3, 20))
78+
79+
delete f.e
80+
>f.e : Symbol(Foo.e, Decl(deleteExpressionMustBeOptional.ts, 4, 14))
81+
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
82+
>e : Symbol(Foo.e, Decl(deleteExpressionMustBeOptional.ts, 4, 14))
83+
84+
delete f.f
85+
>f.f : Symbol(Foo.f, Decl(deleteExpressionMustBeOptional.ts, 5, 32))
86+
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
87+
>f : Symbol(Foo.f, Decl(deleteExpressionMustBeOptional.ts, 5, 32))
88+
89+
delete f.g
90+
>f.g : Symbol(Foo.g, Decl(deleteExpressionMustBeOptional.ts, 6, 33))
91+
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
92+
>g : Symbol(Foo.g, Decl(deleteExpressionMustBeOptional.ts, 6, 33))
93+
94+
delete f.h
95+
>f.h : Symbol(Foo.h, Decl(deleteExpressionMustBeOptional.ts, 7, 14))
96+
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
97+
>h : Symbol(Foo.h, Decl(deleteExpressionMustBeOptional.ts, 7, 14))
98+
99+
delete f.i
100+
>f.i : Symbol(Foo.i, Decl(deleteExpressionMustBeOptional.ts, 8, 10))
101+
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
102+
>i : Symbol(Foo.i, Decl(deleteExpressionMustBeOptional.ts, 8, 10))
103+
104+
delete f.j
105+
>f : Symbol(f, Decl(deleteExpressionMustBeOptional.ts, 20, 13))
106+
107+
delete a.a
108+
>a : Symbol(a, Decl(deleteExpressionMustBeOptional.ts, 21, 13))
109+
110+
delete a.b
111+
>a : Symbol(a, Decl(deleteExpressionMustBeOptional.ts, 21, 13))
112+
113+
delete b.a
114+
>b : Symbol(b, Decl(deleteExpressionMustBeOptional.ts, 22, 13))
115+
116+
delete b.b
117+
>b : Symbol(b, Decl(deleteExpressionMustBeOptional.ts, 22, 13))
118+

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy