Skip to content

Fix 9363: passing undefined or null to parameter destructuring #9425

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

Closed
wants to merge 2 commits into from
Closed
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
15 changes: 15 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10817,6 +10817,15 @@ namespace ts {
argType = arg.kind === SyntaxKind.StringLiteral && !reportErrors
? getStringLiteralTypeForText((<StringLiteral>arg).text)
: checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined);

}

// If the parameter is a destructuring without initializer and argType is undefined, we should give an error
if (argType.flags & (TypeFlags.Undefined | TypeFlags.Null)) {
const parameterDeclaration = getParameterAtPosition(signature, i);
if (parameterDeclaration && !parameterDeclaration.initializer && isBindingPattern(parameterDeclaration.name)) {
error(arg, Diagnostics.Undefined_or_null_is_not_assignable_to_a_destructuring_parameter);
}
}

// Use argument expression as error location when reporting errors
Expand Down Expand Up @@ -11761,6 +11770,12 @@ namespace ts {
return type;
}

function getParameterAtPosition(signature: Signature, pos: number): ParameterDeclaration {
return signature.hasRestParameter ?
pos < signature.parameters.length - 1 ? signature.parameters[pos].valueDeclaration as ParameterDeclaration : undefined :
pos < signature.parameters.length ? signature.parameters[pos].valueDeclaration as ParameterDeclaration : undefined;
}

function getTypeAtPosition(signature: Signature, pos: number): Type {
return signature.hasRestParameter ?
pos < signature.parameters.length - 1 ? getTypeOfParameter(signature.parameters[pos]) : getRestTypeOfSignature(signature) :
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1943,6 +1943,10 @@
"category": "Error",
"code": 2689
},
"'Undefined or 'null' is not assignable to a destructuring parameter.": {
"category": "Error",
"code": 2690
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
"code": 4000
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8ES5.ts(9,5): error TS2690: 'Undefined or 'null' is not assignable to a destructuring parameter.
tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8ES5.ts(11,5): error TS2690: 'Undefined or 'null' is not assignable to a destructuring parameter.
tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8ES5.ts(11,16): error TS2690: 'Undefined or 'null' is not assignable to a destructuring parameter.
tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8ES5.ts(13,5): error TS2690: 'Undefined or 'null' is not assignable to a destructuring parameter.
tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8ES5.ts(15,5): error TS2690: 'Undefined or 'null' is not assignable to a destructuring parameter.
tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8ES5.ts(15,11): error TS2690: 'Undefined or 'null' is not assignable to a destructuring parameter.
tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8ES5.ts(17,5): error TS2690: 'Undefined or 'null' is not assignable to a destructuring parameter.
tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8ES5.ts(17,16): error TS2690: 'Undefined or 'null' is not assignable to a destructuring parameter.
tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8ES5.ts(19,5): error TS2690: 'Undefined or 'null' is not assignable to a destructuring parameter.
tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8ES5.ts(19,11): error TS2690: 'Undefined or 'null' is not assignable to a destructuring parameter.


==== tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration8ES5.ts (10 errors) ====

function one({}, {foo, bar}) {
// ...
}

function two([], [a,b]) {}

// should be an error
one(undefined, { foo: 'foo', bar: 'bar' });
~~~~~~~~~
!!! error TS2690: 'Undefined or 'null' is not assignable to a destructuring parameter.

one(undefined, undefined);
~~~~~~~~~
!!! error TS2690: 'Undefined or 'null' is not assignable to a destructuring parameter.
~~~~~~~~~
!!! error TS2690: 'Undefined or 'null' is not assignable to a destructuring parameter.

one(null, { foo: 'foo', bar: 'bar' });
~~~~
!!! error TS2690: 'Undefined or 'null' is not assignable to a destructuring parameter.

one(null, null);
~~~~
!!! error TS2690: 'Undefined or 'null' is not assignable to a destructuring parameter.
~~~~
!!! error TS2690: 'Undefined or 'null' is not assignable to a destructuring parameter.

two(undefined, undefined);
~~~~~~~~~
!!! error TS2690: 'Undefined or 'null' is not assignable to a destructuring parameter.
~~~~~~~~~
!!! error TS2690: 'Undefined or 'null' is not assignable to a destructuring parameter.

two(null, null);
~~~~
!!! error TS2690: 'Undefined or 'null' is not assignable to a destructuring parameter.
~~~~
!!! error TS2690: 'Undefined or 'null' is not assignable to a destructuring parameter.
36 changes: 36 additions & 0 deletions tests/baselines/reference/destructuringParameterDeclaration8ES5.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//// [destructuringParameterDeclaration8ES5.ts]

function one({}, {foo, bar}) {
// ...
}

function two([], [a,b]) {}

// should be an error
one(undefined, { foo: 'foo', bar: 'bar' });

one(undefined, undefined);

one(null, { foo: 'foo', bar: 'bar' });

one(null, null);

two(undefined, undefined);

two(null, null);

//// [destructuringParameterDeclaration8ES5.js]
function one(_a, _b) {
var foo = _b.foo, bar = _b.bar;
// ...
}
function two(_a, _b) {
var a = _b[0], b = _b[1];
}
// should be an error
one(undefined, { foo: 'foo', bar: 'bar' });
one(undefined, undefined);
one(null, { foo: 'foo', bar: 'bar' });
one(null, null);
two(undefined, undefined);
two(null, null);
28 changes: 28 additions & 0 deletions tests/baselines/reference/destructuringParameterDeclaration9ES5.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//// [destructuringParameterDeclaration9ES5.ts]

function three({} = {}) {}

function four([] = []) {}

// should not be an error

three(undefined);

three(null);

four(undefined);

four(null)

//// [destructuringParameterDeclaration9ES5.js]
function three(_a) {
var _a = {};
}
function four(_a) {
var _a = [];
}
// should not be an error
three(undefined);
three(null);
four(undefined);
four(null);
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
=== tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration9ES5.ts ===

function three({} = {}) {}
>three : Symbol(three, Decl(destructuringParameterDeclaration9ES5.ts, 0, 0))

function four([] = []) {}
>four : Symbol(four, Decl(destructuringParameterDeclaration9ES5.ts, 1, 26))

// should not be an error

three(undefined);
>three : Symbol(three, Decl(destructuringParameterDeclaration9ES5.ts, 0, 0))
>undefined : Symbol(undefined)

three(null);
>three : Symbol(three, Decl(destructuringParameterDeclaration9ES5.ts, 0, 0))

four(undefined);
>four : Symbol(four, Decl(destructuringParameterDeclaration9ES5.ts, 1, 26))
>undefined : Symbol(undefined)

four(null)
>four : Symbol(four, Decl(destructuringParameterDeclaration9ES5.ts, 1, 26))

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
=== tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration9ES5.ts ===

function three({} = {}) {}
>three : ({}?: {}) => void
>{} : {}

function four([] = []) {}
>four : ([]?: any[]) => void
>[] : undefined[]

// should not be an error

three(undefined);
>three(undefined) : void
>three : ({}?: {}) => void
>undefined : undefined

three(null);
>three(null) : void
>three : ({}?: {}) => void
>null : null

four(undefined);
>four(undefined) : void
>four : ([]?: any[]) => void
>undefined : undefined

four(null)
>four(null) : void
>four : ([]?: any[]) => void
>null : null

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// @target: es5

function one({}, {foo, bar}) {
// ...
}

function two([], [a,b]) {}

// should be an error
one(undefined, { foo: 'foo', bar: 'bar' });

one(undefined, undefined);

one(null, { foo: 'foo', bar: 'bar' });

one(null, null);

two(undefined, undefined);

two(null, null);
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// @target: es5

function three({} = {}) {}

function four([] = []) {}

// should not be an error

three(undefined);

three(null);

four(undefined);

four(null)