Skip to content

Fixes #17080 #21328

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13048,7 +13048,7 @@ namespace ts {
node.parent.kind === SyntaxKind.NonNullExpression ||
declaration.kind === SyntaxKind.VariableDeclaration && (<VariableDeclaration>declaration).exclamationToken ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any idea why getRootDeclaration was here? Was this copied from some other source that would also have an erroneous call to it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tracked it back to #14498, which switched to the current narrowing approach that this PR fixes. From my memory of it, I think that I inserted getRootDeclaration during development, then forgot to remove it after changing other parts of the code. Then none of our test cases caught the bug.

declaration.flags & NodeFlags.Ambient;
const initialType = assumeInitialized ? (isParameter ? removeOptionalityFromDeclaredType(type, getRootDeclaration(declaration) as VariableLikeDeclaration) : type) :
const initialType = assumeInitialized ? (isParameter ? removeOptionalityFromDeclaredType(type, declaration as VariableLikeDeclaration) : type) :
type === autoType || type === autoArrayType ? undefinedType :
getOptionalType(type);
const flowType = getFlowTypeOfReference(node, type, initialType, flowContainer, !assumeInitialized);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
tests/cases/compiler/optionalParameterInDestructuringWithInitializer.ts(6,8): error TS2345: Argument of type 'number | undefined' is not assignable to parameter of type 'number'.
Type 'undefined' is not assignable to type 'number'.
tests/cases/compiler/optionalParameterInDestructuringWithInitializer.ts(16,7): error TS2345: Argument of type 'number | undefined' is not assignable to parameter of type 'number'.
Type 'undefined' is not assignable to type 'number'.
tests/cases/compiler/optionalParameterInDestructuringWithInitializer.ts(21,7): error TS2345: Argument of type 'number | undefined' is not assignable to parameter of type 'number'.
Type 'undefined' is not assignable to type 'number'.
tests/cases/compiler/optionalParameterInDestructuringWithInitializer.ts(31,8): error TS2345: Argument of type 'number | undefined' is not assignable to parameter of type 'number'.
Type 'undefined' is not assignable to type 'number'.
tests/cases/compiler/optionalParameterInDestructuringWithInitializer.ts(45,10): error TS2345: Argument of type 'number | undefined' is not assignable to parameter of type 'number'.
Type 'undefined' is not assignable to type 'number'.
tests/cases/compiler/optionalParameterInDestructuringWithInitializer.ts(53,11): error TS2345: Argument of type 'number | null' is not assignable to parameter of type 'number | undefined'.
Type 'null' is not assignable to type 'number | undefined'.


==== tests/cases/compiler/optionalParameterInDestructuringWithInitializer.ts (6 errors) ====
// https://github.com/Microsoft/TypeScript/issues/17080

declare function f(a:number,b:number): void;

function func1( {a, b}: {a: number, b?: number} = {a: 1, b: 2} ) {
f(a, b)
~
!!! error TS2345: Argument of type 'number | undefined' is not assignable to parameter of type 'number'.
!!! error TS2345: Type 'undefined' is not assignable to type 'number'.
// error
}

function func2( {a, b = 3}: {a: number, b?:number} = {a: 1,b: 2} ) {
f(a, b)
// no error
}

function func3( {a, b}: {a: number, b?: number} = {a: 1} ) {
f(a,b)
~
!!! error TS2345: Argument of type 'number | undefined' is not assignable to parameter of type 'number'.
!!! error TS2345: Type 'undefined' is not assignable to type 'number'.
// error
}

function func4( {a: {b, c}, d}: {a: {b: number,c?: number},d: number} = {a: {b: 1,c: 2},d: 3} ) {
f(b,c)
~
!!! error TS2345: Argument of type 'number | undefined' is not assignable to parameter of type 'number'.
!!! error TS2345: Type 'undefined' is not assignable to type 'number'.
// error
}

function func5({a: {b, c = 4}, d}: {a: {b: number,c?: number},d: number} = {a: {b: 1,c: 2},d: 3} ) {
f(b, c)
// no error
}

function func6( {a: {b, c} = {b: 4, c: 5}, d}: {a: {b: number, c?: number}, d: number} = {a: {b: 1,c: 2}, d: 3} ) {
f(b, c)
~
!!! error TS2345: Argument of type 'number | undefined' is not assignable to parameter of type 'number'.
!!! error TS2345: Type 'undefined' is not assignable to type 'number'.
// error
}

function func7( {a: {b, c = 6} = {b: 4, c: 5}, d}: {a: {b: number, c?: number}, d: number} = {a: {b: 1, c: 2}, d: 3} ) {
f(b, c)
// no error
}

interface Foo {
readonly bar?: number;
}

function performFoo({ bar }: Foo = {}) {
useBar(bar);
~~~
!!! error TS2345: Argument of type 'number | undefined' is not assignable to parameter of type 'number'.
!!! error TS2345: Type 'undefined' is not assignable to type 'number'.
}

declare function useBar(bar: number): void;

performFoo();

function performFoo2({ bar = null }: Foo = {}) {
useBar2(bar);
~~~
!!! error TS2345: Argument of type 'number | null' is not assignable to parameter of type 'number | undefined'.
!!! error TS2345: Type 'null' is not assignable to type 'number | undefined'.
}

declare function useBar2(bar: number | undefined): void;

performFoo2();

Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
//// [optionalParameterInDestructuringWithInitializer.ts]
// https://github.com/Microsoft/TypeScript/issues/17080

declare function f(a:number,b:number): void;

function func1( {a, b}: {a: number, b?: number} = {a: 1, b: 2} ) {
f(a, b)
// error
}

function func2( {a, b = 3}: {a: number, b?:number} = {a: 1,b: 2} ) {
f(a, b)
// no error
}

function func3( {a, b}: {a: number, b?: number} = {a: 1} ) {
f(a,b)
// error
}

function func4( {a: {b, c}, d}: {a: {b: number,c?: number},d: number} = {a: {b: 1,c: 2},d: 3} ) {
f(b,c)
// error
}

function func5({a: {b, c = 4}, d}: {a: {b: number,c?: number},d: number} = {a: {b: 1,c: 2},d: 3} ) {
f(b, c)
// no error
}

function func6( {a: {b, c} = {b: 4, c: 5}, d}: {a: {b: number, c?: number}, d: number} = {a: {b: 1,c: 2}, d: 3} ) {
f(b, c)
// error
}

function func7( {a: {b, c = 6} = {b: 4, c: 5}, d}: {a: {b: number, c?: number}, d: number} = {a: {b: 1, c: 2}, d: 3} ) {
f(b, c)
// no error
}

interface Foo {
readonly bar?: number;
}

function performFoo({ bar }: Foo = {}) {
useBar(bar);
}

declare function useBar(bar: number): void;

performFoo();

function performFoo2({ bar = null }: Foo = {}) {
useBar2(bar);
}

declare function useBar2(bar: number | undefined): void;

performFoo2();


//// [optionalParameterInDestructuringWithInitializer.js]
// https://github.com/Microsoft/TypeScript/issues/17080
function func1(_a) {
var _b = _a === void 0 ? { a: 1, b: 2 } : _a, a = _b.a, b = _b.b;
f(a, b);
// error
}
function func2(_a) {
var _b = _a === void 0 ? { a: 1, b: 2 } : _a, a = _b.a, _c = _b.b, b = _c === void 0 ? 3 : _c;
f(a, b);
// no error
}
function func3(_a) {
var _b = _a === void 0 ? { a: 1 } : _a, a = _b.a, b = _b.b;
f(a, b);
// error
}
function func4(_a) {
var _b = _a === void 0 ? { a: { b: 1, c: 2 }, d: 3 } : _a, _c = _b.a, b = _c.b, c = _c.c, d = _b.d;
f(b, c);
// error
}
function func5(_a) {
var _b = _a === void 0 ? { a: { b: 1, c: 2 }, d: 3 } : _a, _c = _b.a, b = _c.b, _d = _c.c, c = _d === void 0 ? 4 : _d, d = _b.d;
f(b, c);
// no error
}
function func6(_a) {
var _b = _a === void 0 ? { a: { b: 1, c: 2 }, d: 3 } : _a, _c = _b.a, _d = _c === void 0 ? { b: 4, c: 5 } : _c, b = _d.b, c = _d.c, d = _b.d;
f(b, c);
// error
}
function func7(_a) {
var _b = _a === void 0 ? { a: { b: 1, c: 2 }, d: 3 } : _a, _c = _b.a, _d = _c === void 0 ? { b: 4, c: 5 } : _c, b = _d.b, _e = _d.c, c = _e === void 0 ? 6 : _e, d = _b.d;
f(b, c);
// no error
}
function performFoo(_a) {
var bar = (_a === void 0 ? {} : _a).bar;
useBar(bar);
}
performFoo();
function performFoo2(_a) {
var _b = (_a === void 0 ? {} : _a).bar, bar = _b === void 0 ? null : _b;
useBar2(bar);
}
performFoo2();
Loading