Merge pull request #22830 from Microsoft/fixDestructuringWithConstraint

Fix control flow analysis for destructuring with constraint
This commit is contained in:
Anders Hejlsberg 2018-03-23 12:47:22 -07:00 committed by GitHub
commit 5daffbbad1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 90 additions and 4 deletions

View File

@ -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;

View File

@ -0,0 +1,20 @@
//// [destructuringWithConstraint.ts]
// Repro from #22823
interface Props {
foo?: boolean;
}
function foo<P extends Props>(props: Readonly<P>) {
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) { }
}

View File

@ -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<P extends Props>(props: Readonly<P>) {
>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))
}

View File

@ -0,0 +1,29 @@
=== tests/cases/compiler/destructuringWithConstraint.ts ===
// Repro from #22823
interface Props {
>Props : Props
foo?: boolean;
>foo : boolean | undefined
}
function foo<P extends Props>(props: Readonly<P>) {
>foo : <P extends Props>(props: Readonly<P>) => void
>P : P
>Props : Props
>props : Readonly<P>
>Readonly : Readonly<T>
>P : P
let { foo = false } = props;
>foo : boolean
>false : false
>props : Readonly<P>
if (foo === true) { }
>foo === true : boolean
>foo : boolean
>true : true
}

View File

@ -0,0 +1,12 @@
// @strict: true
// Repro from #22823
interface Props {
foo?: boolean;
}
function foo<P extends Props>(props: Readonly<P>) {
let { foo = false } = props;
if (foo === true) { }
}