Skip to content

Commit 2abf5a1

Browse files
Guard destructuring initializer contextual typing
Co-authored-by: RyanCavanaugh <[email protected]>
1 parent 43898d2 commit 2abf5a1

File tree

5 files changed

+67
-2
lines changed

5 files changed

+67
-2
lines changed

src/compiler/checker.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28312,7 +28312,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2831228312
// from its initializer, we'll already have cached the type. Otherwise we compute it now
2831328313
// without caching such that transient types are reflected.
2831428314
const links = getNodeLinks(node);
28315-
return links.resolvedType || getTypeOfExpression(node);
28315+
if (links.resolvedType) {
28316+
return links.resolvedType;
28317+
}
28318+
const pattern = isVariableDeclaration(node.parent) && node.parent.initializer === node && isBindingPattern(node.parent.name)
28319+
? node.parent.name
28320+
: undefined;
28321+
if (pattern) {
28322+
contextualBindingPatterns.push(pattern);
28323+
const type = getTypeOfExpression(node);
28324+
contextualBindingPatterns.pop();
28325+
return type;
28326+
}
28327+
return getTypeOfExpression(node);
2831628328
}
2831728329

2831828330
function getInitialTypeOfVariableDeclaration(node: VariableDeclaration) {
@@ -31023,7 +31035,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3102331035
// If the identifier is declared in a binding pattern for which we're currently computing the implied type and the
3102431036
// reference occurs with the same binding pattern, return the non-inferrable any type. This for example occurs in
3102531037
// 'const [a, b = a + 1] = [2]' when we're computing the contextual type for the array literal '[2]'.
31026-
if (declaration && declaration.kind === SyntaxKind.BindingElement && contains(contextualBindingPatterns, declaration.parent) && findAncestor(node, parent => parent === declaration!.parent)) {
31038+
if (declaration && declaration.kind === SyntaxKind.BindingElement && contains(contextualBindingPatterns, declaration.parent)) {
3102731039
return nonInferrableAnyType;
3102831040
}
3102931041

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
destructuringContextualBindingStackOverflow.ts(1,7): error TS2322: Type '{ c: number; f: any; }' is not assignable to type 'string | number | symbol'.
2+
destructuringContextualBindingStackOverflow.ts(1,9): error TS2339: Property 'c' does not exist on type 'string | number | symbol'.
3+
destructuringContextualBindingStackOverflow.ts(1,12): error TS2339: Property 'f' does not exist on type 'string | number | symbol'.
4+
destructuringContextualBindingStackOverflow.ts(1,52): error TS2448: Block-scoped variable 'f' used before its declaration.
5+
6+
7+
==== destructuringContextualBindingStackOverflow.ts (4 errors) ====
8+
const { c, f }: string | number | symbol = { c: 0, f };
9+
~~~~~~~~
10+
!!! error TS2322: Type '{ c: number; f: any; }' is not assignable to type 'string | number | symbol'.
11+
~
12+
!!! error TS2339: Property 'c' does not exist on type 'string | number | symbol'.
13+
~
14+
!!! error TS2339: Property 'f' does not exist on type 'string | number | symbol'.
15+
~
16+
!!! error TS2448: Block-scoped variable 'f' used before its declaration.
17+
!!! related TS2728 destructuringContextualBindingStackOverflow.ts:1:12: 'f' is declared here.
18+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//// [tests/cases/compiler/destructuringContextualBindingStackOverflow.ts] ////
2+
3+
//// [destructuringContextualBindingStackOverflow.ts]
4+
const { c, f }: string | number | symbol = { c: 0, f };
5+
6+
7+
//// [destructuringContextualBindingStackOverflow.js]
8+
"use strict";
9+
var _a = { c: 0, f: f }, c = _a.c, f = _a.f;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//// [tests/cases/compiler/destructuringContextualBindingStackOverflow.ts] ////
2+
3+
=== destructuringContextualBindingStackOverflow.ts ===
4+
const { c, f }: string | number | symbol = { c: 0, f };
5+
>c : Symbol(c, Decl(destructuringContextualBindingStackOverflow.ts, 0, 7))
6+
>f : Symbol(f, Decl(destructuringContextualBindingStackOverflow.ts, 0, 10))
7+
>c : Symbol(c, Decl(destructuringContextualBindingStackOverflow.ts, 0, 44))
8+
>f : Symbol(f, Decl(destructuringContextualBindingStackOverflow.ts, 0, 50))
9+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//// [tests/cases/compiler/destructuringContextualBindingStackOverflow.ts] ////
2+
3+
=== destructuringContextualBindingStackOverflow.ts ===
4+
const { c, f }: string | number | symbol = { c: 0, f };
5+
>c : any
6+
> : ^^^
7+
>f : any
8+
> : ^^^
9+
>{ c: 0, f } : { c: number; f: any; }
10+
> : ^^^^^^^^^^^^^^^^^^^^^^
11+
>c : number
12+
> : ^^^^^^
13+
>0 : 0
14+
> : ^
15+
>f : any
16+
> : ^^^
17+

0 commit comments

Comments
 (0)