Skip to content

Commit 4acdca5

Browse files
committed
Enforce strictNullChecks for RHS of empty destructuring assignment
When strictNullChecks is on, check the RHS of the following destructuring assignments for possible null or undefined: const {} = ... const [] = ... let {} = ... let [] = ... ({} = ...)
1 parent 8bce69e commit 4acdca5

6 files changed

Lines changed: 268 additions & 1 deletion

File tree

src/compiler/checker.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18908,6 +18908,9 @@ namespace ts {
1890818908
target = (<BinaryExpression>target).left;
1890918909
}
1891018910
if (target.kind === SyntaxKind.ObjectLiteralExpression) {
18911+
if (strictNullChecks && (<ObjectLiteralExpression>target).properties.length === 0) {
18912+
return checkNonNullType(sourceType, target);
18913+
}
1891118914
return checkObjectLiteralAssignment(<ObjectLiteralExpression>target, sourceType);
1891218915
}
1891318916
if (target.kind === SyntaxKind.ArrayLiteralExpression) {
@@ -21833,7 +21836,11 @@ namespace ts {
2183321836
if (isBindingPattern(node.name)) {
2183421837
// Don't validate for-in initializer as it is already an error
2183521838
if (node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement) {
21836-
checkTypeAssignableTo(checkExpressionCached(node.initializer), getWidenedTypeForVariableLikeDeclaration(node), node, /*headMessage*/ undefined);
21839+
const initializerType = checkExpressionCached(node.initializer);
21840+
if (strictNullChecks && node.name.elements.length === 0) {
21841+
checkNonNullType(initializerType, node);
21842+
}
21843+
checkTypeAssignableTo(initializerType, getWidenedTypeForVariableLikeDeclaration(node), node, /*headMessage*/ undefined);
2183721844
checkParameterInitializer(node);
2183821845
}
2183921846
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)