Skip to content

Commit 39fee67

Browse files
authored
Merge pull request #21110 from jack-williams/strict-null-empty-destructuring
Fix #20873: Enforce strictNullChecks for RHS of empty destructuring assignment
2 parents 5fcde24 + b16594b commit 39fee67

File tree

6 files changed

+270
-1
lines changed

6 files changed

+270
-1
lines changed

src/compiler/checker.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18375,6 +18375,9 @@ namespace ts {
1837518375

1837618376
function checkObjectLiteralAssignment(node: ObjectLiteralExpression, sourceType: Type): Type {
1837718377
const properties = node.properties;
18378+
if (strictNullChecks && properties.length === 0) {
18379+
return checkNonNullType(sourceType, node);
18380+
}
1837818381
for (const p of properties) {
1837918382
checkObjectLiteralDestructuringPropertyAssignment(sourceType, p, properties);
1838018383
}
@@ -21444,7 +21447,13 @@ namespace ts {
2144421447
if (isBindingPattern(node.name)) {
2144521448
// Don't validate for-in initializer as it is already an error
2144621449
if (node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement) {
21447-
checkTypeAssignableTo(checkExpressionCached(node.initializer), getWidenedTypeForVariableLikeDeclaration(node), node, /*headMessage*/ undefined);
21450+
const initializerType = checkExpressionCached(node.initializer);
21451+
if (strictNullChecks && node.name.elements.length === 0) {
21452+
checkNonNullType(initializerType, node);
21453+
}
21454+
else {
21455+
checkTypeAssignableTo(initializerType, getWidenedTypeForVariableLikeDeclaration(node), node, /*headMessage*/ undefined);
21456+
}
2144821457
checkParameterInitializer(node);
2144921458
}
2145021459
return;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
tests/cases/compiler/strictNullEmptyDestructuring.ts(3,5): error TS2531: Object is possibly 'null'.
2+
tests/cases/compiler/strictNullEmptyDestructuring.ts(5,5): error TS2531: Object is possibly 'null'.
3+
tests/cases/compiler/strictNullEmptyDestructuring.ts(7,2): error TS2531: Object is possibly 'null'.
4+
tests/cases/compiler/strictNullEmptyDestructuring.ts(9,5): error TS2532: Object is possibly 'undefined'.
5+
tests/cases/compiler/strictNullEmptyDestructuring.ts(11,2): error TS2532: Object is possibly 'undefined'.
6+
tests/cases/compiler/strictNullEmptyDestructuring.ts(13,5): error TS2531: Object is possibly 'null'.
7+
tests/cases/compiler/strictNullEmptyDestructuring.ts(15,2): error TS2531: Object is possibly 'null'.
8+
tests/cases/compiler/strictNullEmptyDestructuring.ts(17,5): error TS2532: Object is possibly 'undefined'.
9+
tests/cases/compiler/strictNullEmptyDestructuring.ts(19,2): error TS2532: Object is possibly 'undefined'.
10+
tests/cases/compiler/strictNullEmptyDestructuring.ts(21,5): error TS2533: Object is possibly 'null' or 'undefined'.
11+
tests/cases/compiler/strictNullEmptyDestructuring.ts(23,2): error TS2533: Object is possibly 'null' or 'undefined'.
12+
13+
14+
==== tests/cases/compiler/strictNullEmptyDestructuring.ts (11 errors) ====
15+
// Repro from #20873
16+
17+
let [] = null;
18+
~~
19+
!!! error TS2531: Object is possibly 'null'.
20+
21+
let { } = null;
22+
~~~
23+
!!! error TS2531: Object is possibly 'null'.
24+
25+
({} = null);
26+
~~
27+
!!! error TS2531: Object is possibly 'null'.
28+
29+
let { } = undefined;
30+
~~~
31+
!!! error TS2532: Object is possibly 'undefined'.
32+
33+
({} = undefined);
34+
~~
35+
!!! error TS2532: Object is possibly 'undefined'.
36+
37+
let { } = Math.random() ? {} : null;
38+
~~~
39+
!!! error TS2531: Object is possibly 'null'.
40+
41+
({} = Math.random() ? {} : null);
42+
~~
43+
!!! error TS2531: Object is possibly 'null'.
44+
45+
let { } = Math.random() ? {} : undefined;
46+
~~~
47+
!!! error TS2532: Object is possibly 'undefined'.
48+
49+
({} = Math.random() ? {} : undefined);
50+
~~
51+
!!! error TS2532: Object is possibly 'undefined'.
52+
53+
let { } = Math.random() ? null : undefined;
54+
~~~
55+
!!! error TS2533: Object is possibly 'null' or 'undefined'.
56+
57+
({} = Math.random() ? null : undefined);
58+
~~
59+
!!! error TS2533: Object is possibly 'null' or 'undefined'.
60+
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//// [strictNullEmptyDestructuring.ts]
2+
// Repro from #20873
3+
4+
let [] = null;
5+
6+
let { } = null;
7+
8+
({} = null);
9+
10+
let { } = undefined;
11+
12+
({} = undefined);
13+
14+
let { } = Math.random() ? {} : null;
15+
16+
({} = Math.random() ? {} : null);
17+
18+
let { } = Math.random() ? {} : undefined;
19+
20+
({} = Math.random() ? {} : undefined);
21+
22+
let { } = Math.random() ? null : undefined;
23+
24+
({} = Math.random() ? null : undefined);
25+
26+
27+
//// [strictNullEmptyDestructuring.js]
28+
// Repro from #20873
29+
var _a = null;
30+
var _b = null;
31+
(null);
32+
var _c = undefined;
33+
(undefined);
34+
var _d = Math.random() ? {} : null;
35+
(Math.random() ? {} : null);
36+
var _e = Math.random() ? {} : undefined;
37+
(Math.random() ? {} : undefined);
38+
var _f = Math.random() ? null : undefined;
39+
(Math.random() ? null : undefined);
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
=== tests/cases/compiler/strictNullEmptyDestructuring.ts ===
2+
// Repro from #20873
3+
4+
let [] = null;
5+
6+
let { } = null;
7+
8+
({} = null);
9+
10+
let { } = undefined;
11+
>undefined : Symbol(undefined)
12+
13+
({} = undefined);
14+
>undefined : Symbol(undefined)
15+
16+
let { } = Math.random() ? {} : null;
17+
>Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --))
18+
>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
19+
>random : Symbol(Math.random, Decl(lib.d.ts, --, --))
20+
21+
({} = Math.random() ? {} : null);
22+
>Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --))
23+
>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
24+
>random : Symbol(Math.random, Decl(lib.d.ts, --, --))
25+
26+
let { } = Math.random() ? {} : undefined;
27+
>Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --))
28+
>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
29+
>random : Symbol(Math.random, Decl(lib.d.ts, --, --))
30+
>undefined : Symbol(undefined)
31+
32+
({} = Math.random() ? {} : undefined);
33+
>Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --))
34+
>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
35+
>random : Symbol(Math.random, Decl(lib.d.ts, --, --))
36+
>undefined : Symbol(undefined)
37+
38+
let { } = Math.random() ? null : undefined;
39+
>Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --))
40+
>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
41+
>random : Symbol(Math.random, Decl(lib.d.ts, --, --))
42+
>undefined : Symbol(undefined)
43+
44+
({} = Math.random() ? null : undefined);
45+
>Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --))
46+
>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
47+
>random : Symbol(Math.random, Decl(lib.d.ts, --, --))
48+
>undefined : Symbol(undefined)
49+
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
=== tests/cases/compiler/strictNullEmptyDestructuring.ts ===
2+
// Repro from #20873
3+
4+
let [] = null;
5+
>null : null
6+
7+
let { } = null;
8+
>null : null
9+
10+
({} = null);
11+
>({} = null) : any
12+
>{} = null : any
13+
>{} : {}
14+
>null : null
15+
16+
let { } = undefined;
17+
>undefined : undefined
18+
19+
({} = undefined);
20+
>({} = undefined) : any
21+
>{} = undefined : any
22+
>{} : {}
23+
>undefined : undefined
24+
25+
let { } = Math.random() ? {} : null;
26+
>Math.random() ? {} : null : {} | null
27+
>Math.random() : number
28+
>Math.random : () => number
29+
>Math : Math
30+
>random : () => number
31+
>{} : {}
32+
>null : null
33+
34+
({} = Math.random() ? {} : null);
35+
>({} = Math.random() ? {} : null) : {}
36+
>{} = Math.random() ? {} : null : {}
37+
>{} : {}
38+
>Math.random() ? {} : null : {} | null
39+
>Math.random() : number
40+
>Math.random : () => number
41+
>Math : Math
42+
>random : () => number
43+
>{} : {}
44+
>null : null
45+
46+
let { } = Math.random() ? {} : undefined;
47+
>Math.random() ? {} : undefined : {} | undefined
48+
>Math.random() : number
49+
>Math.random : () => number
50+
>Math : Math
51+
>random : () => number
52+
>{} : {}
53+
>undefined : undefined
54+
55+
({} = Math.random() ? {} : undefined);
56+
>({} = Math.random() ? {} : undefined) : {}
57+
>{} = Math.random() ? {} : undefined : {}
58+
>{} : {}
59+
>Math.random() ? {} : undefined : {} | undefined
60+
>Math.random() : number
61+
>Math.random : () => number
62+
>Math : Math
63+
>random : () => number
64+
>{} : {}
65+
>undefined : undefined
66+
67+
let { } = Math.random() ? null : undefined;
68+
>Math.random() ? null : undefined : null | undefined
69+
>Math.random() : number
70+
>Math.random : () => number
71+
>Math : Math
72+
>random : () => number
73+
>null : null
74+
>undefined : undefined
75+
76+
({} = Math.random() ? null : undefined);
77+
>({} = Math.random() ? null : undefined) : any
78+
>{} = Math.random() ? null : undefined : any
79+
>{} : {}
80+
>Math.random() ? null : undefined : null | undefined
81+
>Math.random() : number
82+
>Math.random : () => number
83+
>Math : Math
84+
>random : () => number
85+
>null : null
86+
>undefined : undefined
87+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// @strictNullChecks: true
2+
3+
// Repro from #20873
4+
5+
let [] = null;
6+
7+
let { } = null;
8+
9+
({} = null);
10+
11+
let { } = undefined;
12+
13+
({} = undefined);
14+
15+
let { } = Math.random() ? {} : null;
16+
17+
({} = Math.random() ? {} : null);
18+
19+
let { } = Math.random() ? {} : undefined;
20+
21+
({} = Math.random() ? {} : undefined);
22+
23+
let { } = Math.random() ? null : undefined;
24+
25+
({} = Math.random() ? null : undefined);

0 commit comments

Comments
 (0)