From c5e680c8be31b0b7651e3ccb078d421e34a76e57 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 29 Jun 2016 09:12:50 -0700 Subject: [PATCH 1/2] Destructuring assignment removes undefined from type when default value is given --- src/compiler/checker.ts | 6 ++++++ .../destructuringAssignmentWithDefault.js | 11 +++++++++++ .../destructuringAssignmentWithDefault.symbols | 12 ++++++++++++ .../destructuringAssignmentWithDefault.types | 17 +++++++++++++++++ .../destructuringAssignmentWithDefault.ts | 4 ++++ 5 files changed, 50 insertions(+) create mode 100644 tests/baselines/reference/destructuringAssignmentWithDefault.js create mode 100644 tests/baselines/reference/destructuringAssignmentWithDefault.symbols create mode 100644 tests/baselines/reference/destructuringAssignmentWithDefault.types create mode 100644 tests/cases/compiler/destructuringAssignmentWithDefault.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 06591a7ab3d44..9ec2ec3309b57 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12544,6 +12544,12 @@ namespace ts { if (exprOrAssignment.kind === SyntaxKind.ShorthandPropertyAssignment) { const prop = exprOrAssignment; if (prop.objectAssignmentInitializer) { + // In strict null checking mode, if a default value of a non-undefined type is specified, remove + // undefined from the final type. + if (strictNullChecks && + !(getCombinedTypeFlags(checkExpressionCached(prop.objectAssignmentInitializer)) & TypeFlags.Undefined)) { + sourceType = getTypeWithFacts(sourceType, TypeFacts.NEUndefined); + } checkBinaryLikeExpression(prop.name, prop.equalsToken, prop.objectAssignmentInitializer, contextualMapper); } target = (exprOrAssignment).name; diff --git a/tests/baselines/reference/destructuringAssignmentWithDefault.js b/tests/baselines/reference/destructuringAssignmentWithDefault.js new file mode 100644 index 0000000000000..ce3837e1162d9 --- /dev/null +++ b/tests/baselines/reference/destructuringAssignmentWithDefault.js @@ -0,0 +1,11 @@ +//// [destructuringAssignmentWithDefault.ts] +const a: { x?: number } = { }; +let x = 0; +({x = 1} = a); + + +//// [destructuringAssignmentWithDefault.js] +var a = {}; +var x = 0; +(_a = a.x, x = _a === void 0 ? 1 : _a, a); +var _a; diff --git a/tests/baselines/reference/destructuringAssignmentWithDefault.symbols b/tests/baselines/reference/destructuringAssignmentWithDefault.symbols new file mode 100644 index 0000000000000..b011834c4f09f --- /dev/null +++ b/tests/baselines/reference/destructuringAssignmentWithDefault.symbols @@ -0,0 +1,12 @@ +=== tests/cases/compiler/destructuringAssignmentWithDefault.ts === +const a: { x?: number } = { }; +>a : Symbol(a, Decl(destructuringAssignmentWithDefault.ts, 0, 5)) +>x : Symbol(x, Decl(destructuringAssignmentWithDefault.ts, 0, 10)) + +let x = 0; +>x : Symbol(x, Decl(destructuringAssignmentWithDefault.ts, 1, 3)) + +({x = 1} = a); +>x : Symbol(x, Decl(destructuringAssignmentWithDefault.ts, 2, 2)) +>a : Symbol(a, Decl(destructuringAssignmentWithDefault.ts, 0, 5)) + diff --git a/tests/baselines/reference/destructuringAssignmentWithDefault.types b/tests/baselines/reference/destructuringAssignmentWithDefault.types new file mode 100644 index 0000000000000..1dc1fe2353343 --- /dev/null +++ b/tests/baselines/reference/destructuringAssignmentWithDefault.types @@ -0,0 +1,17 @@ +=== tests/cases/compiler/destructuringAssignmentWithDefault.ts === +const a: { x?: number } = { }; +>a : { x?: number | undefined; } +>x : number | undefined +>{ } : {} + +let x = 0; +>x : number +>0 : number + +({x = 1} = a); +>({x = 1} = a) : { x?: number | undefined; } +>{x = 1} = a : { x?: number | undefined; } +>{x = 1} : { x?: number; } +>x : number +>a : { x?: number | undefined; } + diff --git a/tests/cases/compiler/destructuringAssignmentWithDefault.ts b/tests/cases/compiler/destructuringAssignmentWithDefault.ts new file mode 100644 index 0000000000000..45ade402eb846 --- /dev/null +++ b/tests/cases/compiler/destructuringAssignmentWithDefault.ts @@ -0,0 +1,4 @@ +// @strictNullChecks: true +const a: { x?: number } = { }; +let x = 0; +({x = 1} = a); From 5f6e25c8d2994694cefc907e50d7ba19f1e07722 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Wed, 29 Jun 2016 18:47:10 -0700 Subject: [PATCH 2/2] Use checkExpression, not checkExpressionCached --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9ec2ec3309b57..0aad4f6196057 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12547,7 +12547,7 @@ namespace ts { // In strict null checking mode, if a default value of a non-undefined type is specified, remove // undefined from the final type. if (strictNullChecks && - !(getCombinedTypeFlags(checkExpressionCached(prop.objectAssignmentInitializer)) & TypeFlags.Undefined)) { + !(getCombinedTypeFlags(checkExpression(prop.objectAssignmentInitializer)) & TypeFlags.Undefined)) { sourceType = getTypeWithFacts(sourceType, TypeFacts.NEUndefined); } checkBinaryLikeExpression(prop.name, prop.equalsToken, prop.objectAssignmentInitializer, contextualMapper);