mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 16:38:05 -06:00
Detect circularities when removing 'undefined' from defaulted params (#37023)
Fixes #37008 Note that referencing a variable in its initializer is a TDZ error; the OP report had OOB logic that prevented this in practice (?)
This commit is contained in:
parent
f7d2beb3f5
commit
c4e96856ac
@ -20522,12 +20522,20 @@ namespace ts {
|
||||
|
||||
/** remove undefined from the annotated type of a parameter when there is an initializer (that doesn't include undefined) */
|
||||
function removeOptionalityFromDeclaredType(declaredType: Type, declaration: VariableLikeDeclaration): Type {
|
||||
const annotationIncludesUndefined = strictNullChecks &&
|
||||
declaration.kind === SyntaxKind.Parameter &&
|
||||
declaration.initializer &&
|
||||
getFalsyFlags(declaredType) & TypeFlags.Undefined &&
|
||||
!(getFalsyFlags(checkExpression(declaration.initializer)) & TypeFlags.Undefined);
|
||||
return annotationIncludesUndefined ? getTypeWithFacts(declaredType, TypeFacts.NEUndefined) : declaredType;
|
||||
if (pushTypeResolution(declaration.symbol, TypeSystemPropertyName.DeclaredType)) {
|
||||
const annotationIncludesUndefined = strictNullChecks &&
|
||||
declaration.kind === SyntaxKind.Parameter &&
|
||||
declaration.initializer &&
|
||||
getFalsyFlags(declaredType) & TypeFlags.Undefined &&
|
||||
!(getFalsyFlags(checkExpression(declaration.initializer)) & TypeFlags.Undefined);
|
||||
popTypeResolution();
|
||||
|
||||
return annotationIncludesUndefined ? getTypeWithFacts(declaredType, TypeFacts.NEUndefined) : declaredType;
|
||||
}
|
||||
else {
|
||||
reportCircularityError(declaration.symbol);
|
||||
return declaredType;
|
||||
}
|
||||
}
|
||||
|
||||
function isConstraintPosition(node: Node) {
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
tests/cases/compiler/circularOptionalityRemoval.ts(2,14): error TS2502: 'x' is referenced directly or indirectly in its own type annotation.
|
||||
tests/cases/compiler/circularOptionalityRemoval.ts(2,38): error TS2372: Parameter 'x' cannot be referenced in its initializer.
|
||||
tests/cases/compiler/circularOptionalityRemoval.ts(2,38): error TS2532: Object is possibly 'undefined'.
|
||||
tests/cases/compiler/circularOptionalityRemoval.ts(2,46): error TS2372: Parameter 'x' cannot be referenced in its initializer.
|
||||
tests/cases/compiler/circularOptionalityRemoval.ts(5,14): error TS1015: Parameter cannot have question mark and initializer.
|
||||
tests/cases/compiler/circularOptionalityRemoval.ts(5,14): error TS2502: 'x' is referenced directly or indirectly in its own type annotation.
|
||||
tests/cases/compiler/circularOptionalityRemoval.ts(5,27): error TS2304: Cannot find name 'someCondition'.
|
||||
tests/cases/compiler/circularOptionalityRemoval.ts(5,54): error TS2372: Parameter 'x' cannot be referenced in its initializer.
|
||||
|
||||
|
||||
==== tests/cases/compiler/circularOptionalityRemoval.ts (8 errors) ====
|
||||
// Constructed repro
|
||||
function fn1(x: number | undefined = x > 0 ? x : 0) { }
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2502: 'x' is referenced directly or indirectly in its own type annotation.
|
||||
~
|
||||
!!! error TS2372: Parameter 'x' cannot be referenced in its initializer.
|
||||
~
|
||||
!!! error TS2532: Object is possibly 'undefined'.
|
||||
~
|
||||
!!! error TS2372: Parameter 'x' cannot be referenced in its initializer.
|
||||
|
||||
// Report from user
|
||||
function fn2(x?: string = someCondition ? 'value1' : x) { }
|
||||
~
|
||||
!!! error TS1015: Parameter cannot have question mark and initializer.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2502: 'x' is referenced directly or indirectly in its own type annotation.
|
||||
~~~~~~~~~~~~~
|
||||
!!! error TS2304: Cannot find name 'someCondition'.
|
||||
~
|
||||
!!! error TS2372: Parameter 'x' cannot be referenced in its initializer.
|
||||
16
tests/baselines/reference/circularOptionalityRemoval.js
Normal file
16
tests/baselines/reference/circularOptionalityRemoval.js
Normal file
@ -0,0 +1,16 @@
|
||||
//// [circularOptionalityRemoval.ts]
|
||||
// Constructed repro
|
||||
function fn1(x: number | undefined = x > 0 ? x : 0) { }
|
||||
|
||||
// Report from user
|
||||
function fn2(x?: string = someCondition ? 'value1' : x) { }
|
||||
|
||||
//// [circularOptionalityRemoval.js]
|
||||
// Constructed repro
|
||||
function fn1(x) {
|
||||
if (x === void 0) { x = x > 0 ? x : 0; }
|
||||
}
|
||||
// Report from user
|
||||
function fn2(x) {
|
||||
if (x === void 0) { x = someCondition ? 'value1' : x; }
|
||||
}
|
||||
14
tests/baselines/reference/circularOptionalityRemoval.symbols
Normal file
14
tests/baselines/reference/circularOptionalityRemoval.symbols
Normal file
@ -0,0 +1,14 @@
|
||||
=== tests/cases/compiler/circularOptionalityRemoval.ts ===
|
||||
// Constructed repro
|
||||
function fn1(x: number | undefined = x > 0 ? x : 0) { }
|
||||
>fn1 : Symbol(fn1, Decl(circularOptionalityRemoval.ts, 0, 0))
|
||||
>x : Symbol(x, Decl(circularOptionalityRemoval.ts, 1, 13))
|
||||
>x : Symbol(x, Decl(circularOptionalityRemoval.ts, 1, 13))
|
||||
>x : Symbol(x, Decl(circularOptionalityRemoval.ts, 1, 13))
|
||||
|
||||
// Report from user
|
||||
function fn2(x?: string = someCondition ? 'value1' : x) { }
|
||||
>fn2 : Symbol(fn2, Decl(circularOptionalityRemoval.ts, 1, 55))
|
||||
>x : Symbol(x, Decl(circularOptionalityRemoval.ts, 4, 13))
|
||||
>x : Symbol(x, Decl(circularOptionalityRemoval.ts, 4, 13))
|
||||
|
||||
21
tests/baselines/reference/circularOptionalityRemoval.types
Normal file
21
tests/baselines/reference/circularOptionalityRemoval.types
Normal file
@ -0,0 +1,21 @@
|
||||
=== tests/cases/compiler/circularOptionalityRemoval.ts ===
|
||||
// Constructed repro
|
||||
function fn1(x: number | undefined = x > 0 ? x : 0) { }
|
||||
>fn1 : (x?: number | undefined) => void
|
||||
>x : number | undefined
|
||||
>x > 0 ? x : 0 : number | undefined
|
||||
>x > 0 : boolean
|
||||
>x : number | undefined
|
||||
>0 : 0
|
||||
>x : number | undefined
|
||||
>0 : 0
|
||||
|
||||
// Report from user
|
||||
function fn2(x?: string = someCondition ? 'value1' : x) { }
|
||||
>fn2 : (x?: string | undefined) => void
|
||||
>x : string | undefined
|
||||
>someCondition ? 'value1' : x : string | undefined
|
||||
>someCondition : any
|
||||
>'value1' : "value1"
|
||||
>x : string | undefined
|
||||
|
||||
7
tests/cases/compiler/circularOptionalityRemoval.ts
Normal file
7
tests/cases/compiler/circularOptionalityRemoval.ts
Normal file
@ -0,0 +1,7 @@
|
||||
// @strictNullChecks: true
|
||||
|
||||
// Constructed repro
|
||||
function fn1(x: number | undefined = x > 0 ? x : 0) { }
|
||||
|
||||
// Report from user
|
||||
function fn2(x?: string = someCondition ? 'value1' : x) { }
|
||||
Loading…
x
Reference in New Issue
Block a user