diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8188e14f5c8..62241eda9d8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -33704,6 +33704,10 @@ namespace ts { if (target.kind === SyntaxKind.BinaryExpression && (target as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) { checkBinaryExpression(target as BinaryExpression, checkMode); target = (target as BinaryExpression).left; + // A default value is specified, so remove undefined from the final type. + if (strictNullChecks) { + sourceType = getTypeWithFacts(sourceType, TypeFacts.NEUndefined); + } } if (target.kind === SyntaxKind.ObjectLiteralExpression) { return checkObjectLiteralAssignment(target as ObjectLiteralExpression, sourceType, rightIsThis); diff --git a/tests/baselines/reference/destructuringAssignmentWithDefault2.errors.txt b/tests/baselines/reference/destructuringAssignmentWithDefault2.errors.txt new file mode 100644 index 00000000000..b77bab849bd --- /dev/null +++ b/tests/baselines/reference/destructuringAssignmentWithDefault2.errors.txt @@ -0,0 +1,42 @@ +tests/cases/compiler/destructuringAssignmentWithDefault2.ts(11,4): error TS2322: Type 'undefined' is not assignable to type 'number'. +tests/cases/compiler/destructuringAssignmentWithDefault2.ts(11,4): error TS2322: Type 'number | undefined' is not assignable to type 'number'. + Type 'undefined' is not assignable to type 'number'. +tests/cases/compiler/destructuringAssignmentWithDefault2.ts(12,7): error TS2322: Type 'undefined' is not assignable to type 'number'. +tests/cases/compiler/destructuringAssignmentWithDefault2.ts(13,7): error TS2322: Type 'undefined' is not assignable to type 'number'. + + +==== tests/cases/compiler/destructuringAssignmentWithDefault2.ts (4 errors) ==== + const a: { x?: number; y?: number } = { }; + + let x: number; + + // Should not error out + ({ x = 0 } = a); + ({ x: x = 0} = a); + ({ y: x = 0} = a); + + // Should be error + ({ x = undefined } = a); + ~ +!!! error TS2322: Type 'undefined' is not assignable to type 'number'. + ~ +!!! error TS2322: Type 'number | undefined' is not assignable to type 'number'. +!!! error TS2322: Type 'undefined' is not assignable to type 'number'. + ({ x: x = undefined } = a); + ~ +!!! error TS2322: Type 'undefined' is not assignable to type 'number'. + ({ y: x = undefined } = a); + ~ +!!! error TS2322: Type 'undefined' is not assignable to type 'number'. + + const { x: z1 } = a; + const { x: z2 = 0 } = a; + const { x: z3 = undefined } = a; + + + declare const r: Iterator; + let done: boolean; + let value; + + ({ done = false, value } = r.next()); + ({ done: done = false, value } = r.next()); \ No newline at end of file diff --git a/tests/baselines/reference/destructuringAssignmentWithDefault2.js b/tests/baselines/reference/destructuringAssignmentWithDefault2.js new file mode 100644 index 00000000000..573dae6cceb --- /dev/null +++ b/tests/baselines/reference/destructuringAssignmentWithDefault2.js @@ -0,0 +1,46 @@ +//// [destructuringAssignmentWithDefault2.ts] +const a: { x?: number; y?: number } = { }; + +let x: number; + +// Should not error out +({ x = 0 } = a); +({ x: x = 0} = a); +({ y: x = 0} = a); + +// Should be error +({ x = undefined } = a); +({ x: x = undefined } = a); +({ y: x = undefined } = a); + +const { x: z1 } = a; +const { x: z2 = 0 } = a; +const { x: z3 = undefined } = a; + + +declare const r: Iterator; +let done: boolean; +let value; + +({ done = false, value } = r.next()); +({ done: done = false, value } = r.next()); + +//// [destructuringAssignmentWithDefault2.js] +var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; +var a = {}; +var x; +// Should not error out +(_a = a.x, x = _a === void 0 ? 0 : _a); +(_b = a.x, x = _b === void 0 ? 0 : _b); +(_c = a.y, x = _c === void 0 ? 0 : _c); +// Should be error +(_d = a.x, x = _d === void 0 ? undefined : _d); +(_e = a.x, x = _e === void 0 ? undefined : _e); +(_f = a.y, x = _f === void 0 ? undefined : _f); +var z1 = a.x; +var _l = a.x, z2 = _l === void 0 ? 0 : _l; +var _m = a.x, z3 = _m === void 0 ? undefined : _m; +var done; +var value; +(_g = r.next(), _h = _g.done, done = _h === void 0 ? false : _h, value = _g.value); +(_j = r.next(), _k = _j.done, done = _k === void 0 ? false : _k, value = _j.value); diff --git a/tests/baselines/reference/destructuringAssignmentWithDefault2.symbols b/tests/baselines/reference/destructuringAssignmentWithDefault2.symbols new file mode 100644 index 00000000000..6a2e9186a6f --- /dev/null +++ b/tests/baselines/reference/destructuringAssignmentWithDefault2.symbols @@ -0,0 +1,84 @@ +=== tests/cases/compiler/destructuringAssignmentWithDefault2.ts === +const a: { x?: number; y?: number } = { }; +>a : Symbol(a, Decl(destructuringAssignmentWithDefault2.ts, 0, 5)) +>x : Symbol(x, Decl(destructuringAssignmentWithDefault2.ts, 0, 10)) +>y : Symbol(y, Decl(destructuringAssignmentWithDefault2.ts, 0, 22)) + +let x: number; +>x : Symbol(x, Decl(destructuringAssignmentWithDefault2.ts, 2, 3)) + +// Should not error out +({ x = 0 } = a); +>x : Symbol(x, Decl(destructuringAssignmentWithDefault2.ts, 5, 2)) +>a : Symbol(a, Decl(destructuringAssignmentWithDefault2.ts, 0, 5)) + +({ x: x = 0} = a); +>x : Symbol(x, Decl(destructuringAssignmentWithDefault2.ts, 6, 2)) +>x : Symbol(x, Decl(destructuringAssignmentWithDefault2.ts, 2, 3)) +>a : Symbol(a, Decl(destructuringAssignmentWithDefault2.ts, 0, 5)) + +({ y: x = 0} = a); +>y : Symbol(y, Decl(destructuringAssignmentWithDefault2.ts, 7, 2)) +>x : Symbol(x, Decl(destructuringAssignmentWithDefault2.ts, 2, 3)) +>a : Symbol(a, Decl(destructuringAssignmentWithDefault2.ts, 0, 5)) + +// Should be error +({ x = undefined } = a); +>x : Symbol(x, Decl(destructuringAssignmentWithDefault2.ts, 10, 2)) +>undefined : Symbol(undefined) +>a : Symbol(a, Decl(destructuringAssignmentWithDefault2.ts, 0, 5)) + +({ x: x = undefined } = a); +>x : Symbol(x, Decl(destructuringAssignmentWithDefault2.ts, 11, 2)) +>x : Symbol(x, Decl(destructuringAssignmentWithDefault2.ts, 2, 3)) +>undefined : Symbol(undefined) +>a : Symbol(a, Decl(destructuringAssignmentWithDefault2.ts, 0, 5)) + +({ y: x = undefined } = a); +>y : Symbol(y, Decl(destructuringAssignmentWithDefault2.ts, 12, 2)) +>x : Symbol(x, Decl(destructuringAssignmentWithDefault2.ts, 2, 3)) +>undefined : Symbol(undefined) +>a : Symbol(a, Decl(destructuringAssignmentWithDefault2.ts, 0, 5)) + +const { x: z1 } = a; +>x : Symbol(x, Decl(destructuringAssignmentWithDefault2.ts, 0, 10)) +>z1 : Symbol(z1, Decl(destructuringAssignmentWithDefault2.ts, 14, 7)) +>a : Symbol(a, Decl(destructuringAssignmentWithDefault2.ts, 0, 5)) + +const { x: z2 = 0 } = a; +>x : Symbol(x, Decl(destructuringAssignmentWithDefault2.ts, 0, 10)) +>z2 : Symbol(z2, Decl(destructuringAssignmentWithDefault2.ts, 15, 7)) +>a : Symbol(a, Decl(destructuringAssignmentWithDefault2.ts, 0, 5)) + +const { x: z3 = undefined } = a; +>x : Symbol(x, Decl(destructuringAssignmentWithDefault2.ts, 0, 10)) +>z3 : Symbol(z3, Decl(destructuringAssignmentWithDefault2.ts, 16, 7)) +>undefined : Symbol(undefined) +>a : Symbol(a, Decl(destructuringAssignmentWithDefault2.ts, 0, 5)) + + +declare const r: Iterator; +>r : Symbol(r, Decl(destructuringAssignmentWithDefault2.ts, 19, 13)) +>Iterator : Symbol(Iterator, Decl(lib.es2015.iterable.d.ts, --, --)) + +let done: boolean; +>done : Symbol(done, Decl(destructuringAssignmentWithDefault2.ts, 20, 3)) + +let value; +>value : Symbol(value, Decl(destructuringAssignmentWithDefault2.ts, 21, 3)) + +({ done = false, value } = r.next()); +>done : Symbol(done, Decl(destructuringAssignmentWithDefault2.ts, 23, 2)) +>value : Symbol(value, Decl(destructuringAssignmentWithDefault2.ts, 23, 16)) +>r.next : Symbol(Iterator.next, Decl(lib.es2015.iterable.d.ts, --, --)) +>r : Symbol(r, Decl(destructuringAssignmentWithDefault2.ts, 19, 13)) +>next : Symbol(Iterator.next, Decl(lib.es2015.iterable.d.ts, --, --)) + +({ done: done = false, value } = r.next()); +>done : Symbol(done, Decl(destructuringAssignmentWithDefault2.ts, 24, 2)) +>done : Symbol(done, Decl(destructuringAssignmentWithDefault2.ts, 20, 3)) +>value : Symbol(value, Decl(destructuringAssignmentWithDefault2.ts, 24, 22)) +>r.next : Symbol(Iterator.next, Decl(lib.es2015.iterable.d.ts, --, --)) +>r : Symbol(r, Decl(destructuringAssignmentWithDefault2.ts, 19, 13)) +>next : Symbol(Iterator.next, Decl(lib.es2015.iterable.d.ts, --, --)) + diff --git a/tests/baselines/reference/destructuringAssignmentWithDefault2.types b/tests/baselines/reference/destructuringAssignmentWithDefault2.types new file mode 100644 index 00000000000..9acf42f3a1b --- /dev/null +++ b/tests/baselines/reference/destructuringAssignmentWithDefault2.types @@ -0,0 +1,121 @@ +=== tests/cases/compiler/destructuringAssignmentWithDefault2.ts === +const a: { x?: number; y?: number } = { }; +>a : { x?: number | undefined; y?: number | undefined; } +>x : number | undefined +>y : number | undefined +>{ } : {} + +let x: number; +>x : number + +// Should not error out +({ x = 0 } = a); +>({ x = 0 } = a) : { x?: number | undefined; y?: number | undefined; } +>{ x = 0 } = a : { x?: number | undefined; y?: number | undefined; } +>{ x = 0 } : { x?: number; } +>x : number +>0 : 0 +>a : { x?: number | undefined; y?: number | undefined; } + +({ x: x = 0} = a); +>({ x: x = 0} = a) : { x?: number | undefined; y?: number | undefined; } +>{ x: x = 0} = a : { x?: number | undefined; y?: number | undefined; } +>{ x: x = 0} : { x?: number; } +>x : number +>x = 0 : 0 +>x : number +>0 : 0 +>a : { x?: number | undefined; y?: number | undefined; } + +({ y: x = 0} = a); +>({ y: x = 0} = a) : { x?: number | undefined; y?: number | undefined; } +>{ y: x = 0} = a : { x?: number | undefined; y?: number | undefined; } +>{ y: x = 0} : { y?: number; } +>y : number +>x = 0 : 0 +>x : number +>0 : 0 +>a : { x?: number | undefined; y?: number | undefined; } + +// Should be error +({ x = undefined } = a); +>({ x = undefined } = a) : { x?: number | undefined; y?: number | undefined; } +>{ x = undefined } = a : { x?: number | undefined; y?: number | undefined; } +>{ x = undefined } : { x?: number; } +>x : number +>undefined : undefined +>a : { x?: number | undefined; y?: number | undefined; } + +({ x: x = undefined } = a); +>({ x: x = undefined } = a) : { x?: number | undefined; y?: number | undefined; } +>{ x: x = undefined } = a : { x?: number | undefined; y?: number | undefined; } +>{ x: x = undefined } : { x?: undefined; } +>x : undefined +>x = undefined : undefined +>x : number +>undefined : undefined +>a : { x?: number | undefined; y?: number | undefined; } + +({ y: x = undefined } = a); +>({ y: x = undefined } = a) : { x?: number | undefined; y?: number | undefined; } +>{ y: x = undefined } = a : { x?: number | undefined; y?: number | undefined; } +>{ y: x = undefined } : { y?: undefined; } +>y : undefined +>x = undefined : undefined +>x : number +>undefined : undefined +>a : { x?: number | undefined; y?: number | undefined; } + +const { x: z1 } = a; +>x : any +>z1 : number | undefined +>a : { x?: number | undefined; y?: number | undefined; } + +const { x: z2 = 0 } = a; +>x : any +>z2 : number +>0 : 0 +>a : { x?: number | undefined; y?: number | undefined; } + +const { x: z3 = undefined } = a; +>x : any +>z3 : number | undefined +>undefined : undefined +>a : { x?: number | undefined; y?: number | undefined; } + + +declare const r: Iterator; +>r : Iterator + +let done: boolean; +>done : boolean + +let value; +>value : any + +({ done = false, value } = r.next()); +>({ done = false, value } = r.next()) : IteratorResult +>{ done = false, value } = r.next() : IteratorResult +>{ done = false, value } : { done?: boolean; value: any; } +>done : boolean +>false : false +>value : any +>r.next() : IteratorResult +>r.next : (...args: [] | [undefined]) => IteratorResult +>r : Iterator +>next : (...args: [] | [undefined]) => IteratorResult + +({ done: done = false, value } = r.next()); +>({ done: done = false, value } = r.next()) : IteratorResult +>{ done: done = false, value } = r.next() : IteratorResult +>{ done: done = false, value } : { done?: boolean; value: any; } +>done : boolean +>done = false : false +>done : boolean +>false : false +>value : any +>r.next() : IteratorResult +>r.next : (...args: [] | [undefined]) => IteratorResult +>r : Iterator +>next : (...args: [] | [undefined]) => IteratorResult + diff --git a/tests/cases/compiler/destructuringAssignmentWithDefault2.ts b/tests/cases/compiler/destructuringAssignmentWithDefault2.ts new file mode 100644 index 00000000000..8dc6fd0a464 --- /dev/null +++ b/tests/cases/compiler/destructuringAssignmentWithDefault2.ts @@ -0,0 +1,27 @@ +// @lib: es2015 +// @strictNullChecks: true +const a: { x?: number; y?: number } = { }; + +let x: number; + +// Should not error out +({ x = 0 } = a); +({ x: x = 0} = a); +({ y: x = 0} = a); + +// Should be error +({ x = undefined } = a); +({ x: x = undefined } = a); +({ y: x = undefined } = a); + +const { x: z1 } = a; +const { x: z2 = 0 } = a; +const { x: z3 = undefined } = a; + + +declare const r: Iterator; +let done: boolean; +let value; + +({ done = false, value } = r.next()); +({ done: done = false, value } = r.next()); \ No newline at end of file