Skip to content

Commit 5daffbb

Browse files
authored
Merge pull request microsoft#22830 from Microsoft/fixDestructuringWithConstraint
Fix control flow analysis for destructuring with constraint
2 parents 02ee11c + ad3b359 commit 5daffbb

File tree

5 files changed

+90
-4
lines changed

5 files changed

+90
-4
lines changed

src/compiler/checker.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -4082,8 +4082,7 @@ namespace ts {
40824082
if (strictNullChecks && declaration.flags & NodeFlags.Ambient && isParameterDeclaration(declaration)) {
40834083
parentType = getNonNullableType(parentType);
40844084
}
4085-
const propType = getTypeOfPropertyOfType(parentType, text);
4086-
const declaredType = propType && getConstraintForLocation(propType, declaration.name);
4085+
const declaredType = getConstraintForLocation(getTypeOfPropertyOfType(parentType, text), declaration.name);
40874086
type = declaredType && getFlowTypeOfReference(declaration, declaredType) ||
40884087
isNumericLiteralName(text) && getIndexTypeOfType(parentType, IndexKind.Number) ||
40894088
getIndexTypeOfType(parentType, IndexKind.String);
@@ -12382,7 +12381,7 @@ namespace ts {
1238212381

1238312382
function getTypeOfDestructuredProperty(type: Type, name: PropertyName) {
1238412383
const text = getTextOfPropertyName(name);
12385-
return getTypeOfPropertyOfType(type, text) ||
12384+
return getConstraintForLocation(getTypeOfPropertyOfType(type, text), name) ||
1238612385
isNumericLiteralName(text) && getIndexTypeOfType(type, IndexKind.Number) ||
1238712386
getIndexTypeOfType(type, IndexKind.String) ||
1238812387
unknownType;
@@ -13498,7 +13497,7 @@ namespace ts {
1349813497
// and the type of the node includes type variables with constraints that are nullable, we fetch the
1349913498
// apparent type of the node *before* performing control flow analysis such that narrowings apply to
1350013499
// the constraint type.
13501-
if (isConstraintPosition(node) && forEachType(type, typeHasNullableConstraint)) {
13500+
if (type && isConstraintPosition(node) && forEachType(type, typeHasNullableConstraint)) {
1350213501
return mapType(getWidenedType(type), getBaseConstraintOrType);
1350313502
}
1350413503
return type;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//// [destructuringWithConstraint.ts]
2+
// Repro from #22823
3+
4+
interface Props {
5+
foo?: boolean;
6+
}
7+
8+
function foo<P extends Props>(props: Readonly<P>) {
9+
let { foo = false } = props;
10+
if (foo === true) { }
11+
}
12+
13+
14+
//// [destructuringWithConstraint.js]
15+
"use strict";
16+
// Repro from #22823
17+
function foo(props) {
18+
var _a = props.foo, foo = _a === void 0 ? false : _a;
19+
if (foo === true) { }
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
=== tests/cases/compiler/destructuringWithConstraint.ts ===
2+
// Repro from #22823
3+
4+
interface Props {
5+
>Props : Symbol(Props, Decl(destructuringWithConstraint.ts, 0, 0))
6+
7+
foo?: boolean;
8+
>foo : Symbol(Props.foo, Decl(destructuringWithConstraint.ts, 2, 17))
9+
}
10+
11+
function foo<P extends Props>(props: Readonly<P>) {
12+
>foo : Symbol(foo, Decl(destructuringWithConstraint.ts, 4, 1))
13+
>P : Symbol(P, Decl(destructuringWithConstraint.ts, 6, 13))
14+
>Props : Symbol(Props, Decl(destructuringWithConstraint.ts, 0, 0))
15+
>props : Symbol(props, Decl(destructuringWithConstraint.ts, 6, 30))
16+
>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --))
17+
>P : Symbol(P, Decl(destructuringWithConstraint.ts, 6, 13))
18+
19+
let { foo = false } = props;
20+
>foo : Symbol(foo, Decl(destructuringWithConstraint.ts, 7, 9))
21+
>props : Symbol(props, Decl(destructuringWithConstraint.ts, 6, 30))
22+
23+
if (foo === true) { }
24+
>foo : Symbol(foo, Decl(destructuringWithConstraint.ts, 7, 9))
25+
}
26+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
=== tests/cases/compiler/destructuringWithConstraint.ts ===
2+
// Repro from #22823
3+
4+
interface Props {
5+
>Props : Props
6+
7+
foo?: boolean;
8+
>foo : boolean | undefined
9+
}
10+
11+
function foo<P extends Props>(props: Readonly<P>) {
12+
>foo : <P extends Props>(props: Readonly<P>) => void
13+
>P : P
14+
>Props : Props
15+
>props : Readonly<P>
16+
>Readonly : Readonly<T>
17+
>P : P
18+
19+
let { foo = false } = props;
20+
>foo : boolean
21+
>false : false
22+
>props : Readonly<P>
23+
24+
if (foo === true) { }
25+
>foo === true : boolean
26+
>foo : boolean
27+
>true : true
28+
}
29+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// @strict: true
2+
3+
// Repro from #22823
4+
5+
interface Props {
6+
foo?: boolean;
7+
}
8+
9+
function foo<P extends Props>(props: Readonly<P>) {
10+
let { foo = false } = props;
11+
if (foo === true) { }
12+
}

0 commit comments

Comments
 (0)