Skip to content

Commit

Permalink
Fixed an issue with destructured bindings from a generic union constr…
Browse files Browse the repository at this point in the history
…aint not being narrowed correctly (#50221)
  • Loading branch information
Andarist committed Sep 17, 2022
1 parent 08af0b6 commit a8e13f7
Show file tree
Hide file tree
Showing 6 changed files with 523 additions and 322 deletions.
5 changes: 3 additions & 2 deletions src/compiler/checker.ts
Expand Up @@ -25924,10 +25924,11 @@ namespace ts {
if (!(links.flags & NodeCheckFlags.InCheckIdentifier)) {
links.flags |= NodeCheckFlags.InCheckIdentifier;
const parentType = getTypeForBindingElementParent(parent, CheckMode.Normal);
const parentTypeConstraint = parentType && mapType(parentType, getBaseConstraintOrType);
links.flags &= ~NodeCheckFlags.InCheckIdentifier;
if (parentType && parentType.flags & TypeFlags.Union && !(parent.kind === SyntaxKind.Parameter && isSymbolAssigned(symbol))) {
if (parentTypeConstraint && parentTypeConstraint.flags & TypeFlags.Union && !(parent.kind === SyntaxKind.Parameter && isSymbolAssigned(symbol))) {
const pattern = declaration.parent;
const narrowedType = getFlowTypeOfReference(pattern, parentType, parentType, /*flowContainer*/ undefined, location.flowNode);
const narrowedType = getFlowTypeOfReference(pattern, parentTypeConstraint, parentTypeConstraint, /*flowContainer*/ undefined, location.flowNode);
if (narrowedType.flags & TypeFlags.Never) {
return neverType;
}
Expand Down
@@ -1,5 +1,5 @@
tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(314,5): error TS7022: 'value1' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(314,5): error TS7031: Binding element 'value1' implicitly has an 'any' type.
tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(334,5): error TS7022: 'value1' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(334,5): error TS7031: Binding element 'value1' implicitly has an 'any' type.


==== tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts (2 errors) ====
Expand Down Expand Up @@ -39,6 +39,26 @@ tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(314,5): er
}
}

// repro #50206
function f13<T extends Action>({ kind, payload }: T) {
if (kind === 'A') {
payload.toFixed();
}
if (kind === 'B') {
payload.toUpperCase();
}
}

function f14<T extends Action>(t: T) {
const { kind, payload } = t;
if (kind === 'A') {
payload.toFixed();
}
if (kind === 'B') {
payload.toUpperCase();
}
}

type Action2 =
| { kind: 'A', payload: number | undefined }
| { kind: 'B', payload: string | undefined };
Expand Down
40 changes: 40 additions & 0 deletions tests/baselines/reference/dependentDestructuredVariables.js
Expand Up @@ -35,6 +35,26 @@ function f12({ kind, payload }: Action) {
}
}

// repro #50206
function f13<T extends Action>({ kind, payload }: T) {
if (kind === 'A') {
payload.toFixed();
}
if (kind === 'B') {
payload.toUpperCase();
}
}

function f14<T extends Action>(t: T) {
const { kind, payload } = t;
if (kind === 'A') {
payload.toFixed();
}
if (kind === 'B') {
payload.toUpperCase();
}
}

type Action2 =
| { kind: 'A', payload: number | undefined }
| { kind: 'B', payload: string | undefined };
Expand Down Expand Up @@ -420,6 +440,24 @@ function f12({ kind, payload }) {
payload; // never
}
}
// repro #50206
function f13({ kind, payload }) {
if (kind === 'A') {
payload.toFixed();
}
if (kind === 'B') {
payload.toUpperCase();
}
}
function f14(t) {
const { kind, payload } = t;
if (kind === 'A') {
payload.toFixed();
}
if (kind === 'B') {
payload.toUpperCase();
}
}
function f20({ kind, payload }) {
if (payload) {
if (kind === 'A') {
Expand Down Expand Up @@ -662,6 +700,8 @@ type Action = {
declare function f10({ kind, payload }: Action): void;
declare function f11(action: Action): void;
declare function f12({ kind, payload }: Action): void;
declare function f13<T extends Action>({ kind, payload }: T): void;
declare function f14<T extends Action>(t: T): void;
type Action2 = {
kind: 'A';
payload: number | undefined;
Expand Down

0 comments on commit a8e13f7

Please sign in to comment.