Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
20 changes: 20 additions & 0 deletions tests/baselines/reference/destructuringWithConstraint.js
Original file line number Diff line number Diff line change
@@ -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) { }
}
26 changes: 26 additions & 0 deletions tests/baselines/reference/destructuringWithConstraint.symbols
Original file line number Diff line number Diff line change
@@ -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))
}

29 changes: 29 additions & 0 deletions tests/baselines/reference/destructuringWithConstraint.types
Original file line number Diff line number Diff line change
@@ -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
}

12 changes: 12 additions & 0 deletions tests/cases/compiler/destructuringWithConstraint.ts
Original file line number Diff line number Diff line change
@@ -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) { }
}