mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-04-17 01:49:41 -05:00
fix(50551): Destructuring assignment with var bypasses "variable is used before being assigned" check (2454) (#50560)
* fix(50551): handle destructuring variables used before assignment * skip the error in binding elements that refer to the same destructuring * fix binding element type
This commit is contained in:
@@ -26289,7 +26289,7 @@ namespace ts {
|
||||
// We only look for uninitialized variables in strict null checking mode, and only when we can analyze
|
||||
// the entire control flow graph from the variable's declaration (i.e. when the flow container and
|
||||
// declaration container are the same).
|
||||
const assumeInitialized = isParameter || isAlias || isOuterVariable || isSpreadDestructuringAssignmentTarget || isModuleExports || isBindingElement(declaration) ||
|
||||
const assumeInitialized = isParameter || isAlias || isOuterVariable || isSpreadDestructuringAssignmentTarget || isModuleExports || isSameScopedBindingElement(node, declaration) ||
|
||||
type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.Void)) !== 0 ||
|
||||
isInTypeQuery(node) || node.parent.kind === SyntaxKind.ExportSpecifier) ||
|
||||
node.parent.kind === SyntaxKind.NonNullExpression ||
|
||||
@@ -26319,6 +26319,13 @@ namespace ts {
|
||||
return assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType;
|
||||
}
|
||||
|
||||
function isSameScopedBindingElement(node: Identifier, declaration: Declaration) {
|
||||
if (isBindingElement(declaration)) {
|
||||
const bindingElement = findAncestor(node, isBindingElement);
|
||||
return bindingElement && getRootDeclaration(bindingElement) === getRootDeclaration(declaration);
|
||||
}
|
||||
}
|
||||
|
||||
function shouldMarkIdentifierAliasReferenced(node: Identifier): boolean {
|
||||
const parent = node.parent;
|
||||
if (parent) {
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
tests/cases/compiler/controlFlowDestructuringVariablesInTryCatch.ts(16,1): error TS2454: Variable 'a' is used before being assigned.
|
||||
tests/cases/compiler/controlFlowDestructuringVariablesInTryCatch.ts(17,1): error TS2454: Variable 'b' is used before being assigned.
|
||||
tests/cases/compiler/controlFlowDestructuringVariablesInTryCatch.ts(18,1): error TS2454: Variable 'c' is used before being assigned.
|
||||
tests/cases/compiler/controlFlowDestructuringVariablesInTryCatch.ts(19,1): error TS2454: Variable 'd' is used before being assigned.
|
||||
tests/cases/compiler/controlFlowDestructuringVariablesInTryCatch.ts(20,1): error TS2454: Variable 'e' is used before being assigned.
|
||||
|
||||
|
||||
==== tests/cases/compiler/controlFlowDestructuringVariablesInTryCatch.ts (5 errors) ====
|
||||
declare function f1(): string;
|
||||
declare function f2(): [b: string];
|
||||
declare function f3(): { c: string };
|
||||
|
||||
try {
|
||||
var a = f1();
|
||||
var [b] = f2();
|
||||
var { c } = f3();
|
||||
|
||||
var [d = 1] = [];
|
||||
var { e = 1 } = { };
|
||||
} catch {
|
||||
console.error("error");
|
||||
}
|
||||
|
||||
a;
|
||||
~
|
||||
!!! error TS2454: Variable 'a' is used before being assigned.
|
||||
b;
|
||||
~
|
||||
!!! error TS2454: Variable 'b' is used before being assigned.
|
||||
c;
|
||||
~
|
||||
!!! error TS2454: Variable 'c' is used before being assigned.
|
||||
d;
|
||||
~
|
||||
!!! error TS2454: Variable 'd' is used before being assigned.
|
||||
e;
|
||||
~
|
||||
!!! error TS2454: Variable 'e' is used before being assigned.
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
//// [controlFlowDestructuringVariablesInTryCatch.ts]
|
||||
declare function f1(): string;
|
||||
declare function f2(): [b: string];
|
||||
declare function f3(): { c: string };
|
||||
|
||||
try {
|
||||
var a = f1();
|
||||
var [b] = f2();
|
||||
var { c } = f3();
|
||||
|
||||
var [d = 1] = [];
|
||||
var { e = 1 } = { };
|
||||
} catch {
|
||||
console.error("error");
|
||||
}
|
||||
|
||||
a;
|
||||
b;
|
||||
c;
|
||||
d;
|
||||
e;
|
||||
|
||||
|
||||
//// [controlFlowDestructuringVariablesInTryCatch.js]
|
||||
"use strict";
|
||||
try {
|
||||
var a = f1();
|
||||
var b = f2()[0];
|
||||
var c = f3().c;
|
||||
var _a = [][0], d = _a === void 0 ? 1 : _a;
|
||||
var _b = {}.e, e = _b === void 0 ? 1 : _b;
|
||||
}
|
||||
catch (_c) {
|
||||
console.error("error");
|
||||
}
|
||||
a;
|
||||
b;
|
||||
c;
|
||||
d;
|
||||
e;
|
||||
@@ -0,0 +1,52 @@
|
||||
=== tests/cases/compiler/controlFlowDestructuringVariablesInTryCatch.ts ===
|
||||
declare function f1(): string;
|
||||
>f1 : Symbol(f1, Decl(controlFlowDestructuringVariablesInTryCatch.ts, 0, 0))
|
||||
|
||||
declare function f2(): [b: string];
|
||||
>f2 : Symbol(f2, Decl(controlFlowDestructuringVariablesInTryCatch.ts, 0, 30))
|
||||
|
||||
declare function f3(): { c: string };
|
||||
>f3 : Symbol(f3, Decl(controlFlowDestructuringVariablesInTryCatch.ts, 1, 35))
|
||||
>c : Symbol(c, Decl(controlFlowDestructuringVariablesInTryCatch.ts, 2, 24))
|
||||
|
||||
try {
|
||||
var a = f1();
|
||||
>a : Symbol(a, Decl(controlFlowDestructuringVariablesInTryCatch.ts, 5, 7))
|
||||
>f1 : Symbol(f1, Decl(controlFlowDestructuringVariablesInTryCatch.ts, 0, 0))
|
||||
|
||||
var [b] = f2();
|
||||
>b : Symbol(b, Decl(controlFlowDestructuringVariablesInTryCatch.ts, 6, 9))
|
||||
>f2 : Symbol(f2, Decl(controlFlowDestructuringVariablesInTryCatch.ts, 0, 30))
|
||||
|
||||
var { c } = f3();
|
||||
>c : Symbol(c, Decl(controlFlowDestructuringVariablesInTryCatch.ts, 7, 9))
|
||||
>f3 : Symbol(f3, Decl(controlFlowDestructuringVariablesInTryCatch.ts, 1, 35))
|
||||
|
||||
var [d = 1] = [];
|
||||
>d : Symbol(d, Decl(controlFlowDestructuringVariablesInTryCatch.ts, 9, 9))
|
||||
|
||||
var { e = 1 } = { };
|
||||
>e : Symbol(e, Decl(controlFlowDestructuringVariablesInTryCatch.ts, 10, 9))
|
||||
|
||||
} catch {
|
||||
console.error("error");
|
||||
>console.error : Symbol(Console.error, Decl(lib.dom.d.ts, --, --))
|
||||
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
|
||||
>error : Symbol(Console.error, Decl(lib.dom.d.ts, --, --))
|
||||
}
|
||||
|
||||
a;
|
||||
>a : Symbol(a, Decl(controlFlowDestructuringVariablesInTryCatch.ts, 5, 7))
|
||||
|
||||
b;
|
||||
>b : Symbol(b, Decl(controlFlowDestructuringVariablesInTryCatch.ts, 6, 9))
|
||||
|
||||
c;
|
||||
>c : Symbol(c, Decl(controlFlowDestructuringVariablesInTryCatch.ts, 7, 9))
|
||||
|
||||
d;
|
||||
>d : Symbol(d, Decl(controlFlowDestructuringVariablesInTryCatch.ts, 9, 9))
|
||||
|
||||
e;
|
||||
>e : Symbol(e, Decl(controlFlowDestructuringVariablesInTryCatch.ts, 10, 9))
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
=== tests/cases/compiler/controlFlowDestructuringVariablesInTryCatch.ts ===
|
||||
declare function f1(): string;
|
||||
>f1 : () => string
|
||||
|
||||
declare function f2(): [b: string];
|
||||
>f2 : () => [b: string]
|
||||
|
||||
declare function f3(): { c: string };
|
||||
>f3 : () => { c: string; }
|
||||
>c : string
|
||||
|
||||
try {
|
||||
var a = f1();
|
||||
>a : string
|
||||
>f1() : string
|
||||
>f1 : () => string
|
||||
|
||||
var [b] = f2();
|
||||
>b : string
|
||||
>f2() : [b: string]
|
||||
>f2 : () => [b: string]
|
||||
|
||||
var { c } = f3();
|
||||
>c : string
|
||||
>f3() : { c: string; }
|
||||
>f3 : () => { c: string; }
|
||||
|
||||
var [d = 1] = [];
|
||||
>d : number
|
||||
>1 : 1
|
||||
>[] : []
|
||||
|
||||
var { e = 1 } = { };
|
||||
>e : number
|
||||
>1 : 1
|
||||
>{ } : { e?: number | undefined; }
|
||||
|
||||
} catch {
|
||||
console.error("error");
|
||||
>console.error("error") : void
|
||||
>console.error : (...data: any[]) => void
|
||||
>console : Console
|
||||
>error : (...data: any[]) => void
|
||||
>"error" : "error"
|
||||
}
|
||||
|
||||
a;
|
||||
>a : string
|
||||
|
||||
b;
|
||||
>b : string
|
||||
|
||||
c;
|
||||
>c : string
|
||||
|
||||
d;
|
||||
>d : number
|
||||
|
||||
e;
|
||||
>e : number
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
//// [controlFlowInitializedDestructuringVariables.ts]
|
||||
declare const obj: { a?: string, b?: number };
|
||||
const {
|
||||
a = "0",
|
||||
b = +a,
|
||||
} = obj;
|
||||
|
||||
|
||||
//// [controlFlowInitializedDestructuringVariables.js]
|
||||
"use strict";
|
||||
var _a = obj.a, a = _a === void 0 ? "0" : _a, _b = obj.b, b = _b === void 0 ? +a : _b;
|
||||
@@ -0,0 +1,17 @@
|
||||
=== tests/cases/compiler/controlFlowInitializedDestructuringVariables.ts ===
|
||||
declare const obj: { a?: string, b?: number };
|
||||
>obj : Symbol(obj, Decl(controlFlowInitializedDestructuringVariables.ts, 0, 13))
|
||||
>a : Symbol(a, Decl(controlFlowInitializedDestructuringVariables.ts, 0, 20))
|
||||
>b : Symbol(b, Decl(controlFlowInitializedDestructuringVariables.ts, 0, 32))
|
||||
|
||||
const {
|
||||
a = "0",
|
||||
>a : Symbol(a, Decl(controlFlowInitializedDestructuringVariables.ts, 1, 7))
|
||||
|
||||
b = +a,
|
||||
>b : Symbol(b, Decl(controlFlowInitializedDestructuringVariables.ts, 2, 12))
|
||||
>a : Symbol(a, Decl(controlFlowInitializedDestructuringVariables.ts, 1, 7))
|
||||
|
||||
} = obj;
|
||||
>obj : Symbol(obj, Decl(controlFlowInitializedDestructuringVariables.ts, 0, 13))
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
=== tests/cases/compiler/controlFlowInitializedDestructuringVariables.ts ===
|
||||
declare const obj: { a?: string, b?: number };
|
||||
>obj : { a?: string | undefined; b?: number | undefined; }
|
||||
>a : string | undefined
|
||||
>b : number | undefined
|
||||
|
||||
const {
|
||||
a = "0",
|
||||
>a : string
|
||||
>"0" : "0"
|
||||
|
||||
b = +a,
|
||||
>b : number
|
||||
>+a : number
|
||||
>a : string
|
||||
|
||||
} = obj;
|
||||
>obj : { a?: string | undefined; b?: number | undefined; }
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// @strict: true
|
||||
|
||||
declare function f1(): string;
|
||||
declare function f2(): [b: string];
|
||||
declare function f3(): { c: string };
|
||||
|
||||
try {
|
||||
var a = f1();
|
||||
var [b] = f2();
|
||||
var { c } = f3();
|
||||
|
||||
var [d = 1] = [];
|
||||
var { e = 1 } = { };
|
||||
} catch {
|
||||
console.error("error");
|
||||
}
|
||||
|
||||
a;
|
||||
b;
|
||||
c;
|
||||
d;
|
||||
e;
|
||||
@@ -0,0 +1,7 @@
|
||||
// @strict: true
|
||||
|
||||
declare const obj: { a?: string, b?: number };
|
||||
const {
|
||||
a = "0",
|
||||
b = +a,
|
||||
} = obj;
|
||||
Reference in New Issue
Block a user