From deb87bb8ada5671c1c8cfeec03b3784a9abd04db Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 23 Mar 2018 09:42:43 -0700 Subject: [PATCH 1/3] Obtain constraint from destructured property when applicable --- src/compiler/checker.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) 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; From 1c2f3d228cf5634c7afc5bb6501074837358a9bb Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 23 Mar 2018 09:48:00 -0700 Subject: [PATCH 2/3] Add regression test --- tests/cases/compiler/destructuringWithConstraint.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/cases/compiler/destructuringWithConstraint.ts 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) { } +} From ad3b3597e43c3256e78a82704bf767a5433c9a76 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 23 Mar 2018 09:48:11 -0700 Subject: [PATCH 3/3] Accept new baselines --- .../reference/destructuringWithConstraint.js | 20 +++++++++++++ .../destructuringWithConstraint.symbols | 26 +++++++++++++++++ .../destructuringWithConstraint.types | 29 +++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 tests/baselines/reference/destructuringWithConstraint.js create mode 100644 tests/baselines/reference/destructuringWithConstraint.symbols create mode 100644 tests/baselines/reference/destructuringWithConstraint.types 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 +>P : P + + let { foo = false } = props; +>foo : boolean +>false : false +>props : Readonly

+ + if (foo === true) { } +>foo === true : boolean +>foo : boolean +>true : true +} +