diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 29a555ee29705..65807b5347b86 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4082,8 +4082,7 @@ namespace ts { if (strictNullChecks && declaration.flags & NodeFlags.Ambient && isParameterDeclaration(declaration)) { parentType = getNonNullableType(parentType); } - const propType = getTypeOfPropertyOfType(parentType, text); - const declaredType = propType && getConstraintForLocation(propType, declaration.name); + const declaredType = getConstraintForLocation(getTypeOfPropertyOfType(parentType, text), declaration.name); type = declaredType && getFlowTypeOfReference(declaration, declaredType) || isNumericLiteralName(text) && getIndexTypeOfType(parentType, IndexKind.Number) || getIndexTypeOfType(parentType, IndexKind.String); @@ -12382,7 +12381,7 @@ namespace ts { function getTypeOfDestructuredProperty(type: Type, name: PropertyName) { const text = getTextOfPropertyName(name); - return getTypeOfPropertyOfType(type, text) || + return getConstraintForLocation(getTypeOfPropertyOfType(type, text), name) || isNumericLiteralName(text) && getIndexTypeOfType(type, IndexKind.Number) || getIndexTypeOfType(type, IndexKind.String) || unknownType; @@ -13498,7 +13497,7 @@ namespace ts { // and the type of the node includes type variables with constraints that are nullable, we fetch the // apparent type of the node *before* performing control flow analysis such that narrowings apply to // the constraint type. - if (isConstraintPosition(node) && forEachType(type, typeHasNullableConstraint)) { + if (type && isConstraintPosition(node) && forEachType(type, typeHasNullableConstraint)) { return mapType(getWidenedType(type), getBaseConstraintOrType); } return type; diff --git a/tests/baselines/reference/destructuringWithConstraint.js b/tests/baselines/reference/destructuringWithConstraint.js new file mode 100644 index 0000000000000..2d28971b67893 --- /dev/null +++ b/tests/baselines/reference/destructuringWithConstraint.js @@ -0,0 +1,20 @@ +//// [destructuringWithConstraint.ts] +// Repro from #22823 + +interface Props { + foo?: boolean; +} + +function foo
(props: Readonly
) { + let { foo = false } = props; + if (foo === true) { } +} + + +//// [destructuringWithConstraint.js] +"use strict"; +// Repro from #22823 +function foo(props) { + var _a = props.foo, foo = _a === void 0 ? false : _a; + if (foo === true) { } +} diff --git a/tests/baselines/reference/destructuringWithConstraint.symbols b/tests/baselines/reference/destructuringWithConstraint.symbols new file mode 100644 index 0000000000000..aef7aad768e4e --- /dev/null +++ b/tests/baselines/reference/destructuringWithConstraint.symbols @@ -0,0 +1,26 @@ +=== tests/cases/compiler/destructuringWithConstraint.ts === +// Repro from #22823 + +interface Props { +>Props : Symbol(Props, Decl(destructuringWithConstraint.ts, 0, 0)) + + foo?: boolean; +>foo : Symbol(Props.foo, Decl(destructuringWithConstraint.ts, 2, 17)) +} + +function foo
(props: Readonly
) { +>foo : Symbol(foo, Decl(destructuringWithConstraint.ts, 4, 1)) +>P : Symbol(P, Decl(destructuringWithConstraint.ts, 6, 13)) +>Props : Symbol(Props, Decl(destructuringWithConstraint.ts, 0, 0)) +>props : Symbol(props, Decl(destructuringWithConstraint.ts, 6, 30)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>P : Symbol(P, Decl(destructuringWithConstraint.ts, 6, 13)) + + let { foo = false } = props; +>foo : Symbol(foo, Decl(destructuringWithConstraint.ts, 7, 9)) +>props : Symbol(props, Decl(destructuringWithConstraint.ts, 6, 30)) + + if (foo === true) { } +>foo : Symbol(foo, Decl(destructuringWithConstraint.ts, 7, 9)) +} + diff --git a/tests/baselines/reference/destructuringWithConstraint.types b/tests/baselines/reference/destructuringWithConstraint.types new file mode 100644 index 0000000000000..a58745a6481b2 --- /dev/null +++ b/tests/baselines/reference/destructuringWithConstraint.types @@ -0,0 +1,29 @@ +=== tests/cases/compiler/destructuringWithConstraint.ts === +// Repro from #22823 + +interface Props { +>Props : Props + + foo?: boolean; +>foo : boolean | undefined +} + +function foo
(props: Readonly
) { +>foo :
(props: Readonly
) => void +>P : P +>Props : Props +>props : Readonly
+>Readonly : Readonly
+
+ if (foo === true) { }
+>foo === true : boolean
+>foo : boolean
+>true : true
+}
+
diff --git a/tests/cases/compiler/destructuringWithConstraint.ts b/tests/cases/compiler/destructuringWithConstraint.ts
new file mode 100644
index 0000000000000..505cab86c9767
--- /dev/null
+++ b/tests/cases/compiler/destructuringWithConstraint.ts
@@ -0,0 +1,12 @@
+// @strict: true
+
+// Repro from #22823
+
+interface Props {
+ foo?: boolean;
+}
+
+function foo (props: Readonly ) {
+ let { foo = false } = props;
+ if (foo === true) { }
+}