From 85ddc297c2643b1dbc32527ef672c03135a3dd52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Zugmeyer?= Date: Fri, 17 Jan 2020 21:00:37 +0100 Subject: [PATCH] Fix rest parameters indexing with TypeScript 'this parameter' (#9714) * Fix rest parameters indexing with TypeScript 'this parameter' The TypeScript [this parameter][0] is a fake parameter and should not be taken into account when counting the function parameters. This patch skips it by using the condition taken from the `transform-typescript` plugin. Note: since the `transform-typescript` plugin is removing this kind of parameter, including it before the `transform-parameters` plugin solves the issue. This patch fixes the issue in other cases. [0]: https://www.typescriptlang.org/docs/handbook/functions.html#this-parameters * nit: improve the 'this parameter' detection condition * improve performance by checking the parameter list length before accessing it * simplify the test a bit by using the `isIdentifier` second parameter --- .../src/rest.js | 18 +++++++++++++++--- .../test/fixtures/parameters/options.json | 1 + .../parameters/rest-ts-this-parameter/input.js | 7 +++++++ .../rest-ts-this-parameter/output.js | 11 +++++++++++ 4 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 packages/babel-plugin-transform-parameters/test/fixtures/parameters/rest-ts-this-parameter/input.js create mode 100644 packages/babel-plugin-transform-parameters/test/fixtures/parameters/rest-ts-this-parameter/output.js diff --git a/packages/babel-plugin-transform-parameters/src/rest.js b/packages/babel-plugin-transform-parameters/src/rest.js index eccd548aec..cfba76ce4a 100644 --- a/packages/babel-plugin-transform-parameters/src/rest.js +++ b/packages/babel-plugin-transform-parameters/src/rest.js @@ -155,6 +155,16 @@ const memberExpressionOptimisationVisitor = { } }, }; + +function getParamsCount(node) { + let count = node.params.length; + // skip the first parameter if it is a TypeScript 'this parameter' + if (count > 0 && t.isIdentifier(node.params[0], { name: "this" })) { + count -= 1; + } + return count; +} + function hasRest(node) { const length = node.params.length; return length > 0 && t.isRestElement(node.params[length - 1]); @@ -244,10 +254,12 @@ export default function convertFunctionRest(path) { node.body.body.unshift(declar); } + const paramsCount = getParamsCount(node); + // check and optimise for extremely common cases const state = { references: [], - offset: node.params.length, + offset: paramsCount, argumentsNode: argsId, outerBinding: scope.getBindingIdentifier(rest.name), @@ -297,12 +309,12 @@ export default function convertFunctionRest(path) { state.candidates.map(({ path }) => path), ); - const start = t.numericLiteral(node.params.length); + const start = t.numericLiteral(paramsCount); const key = scope.generateUidIdentifier("key"); const len = scope.generateUidIdentifier("len"); let arrKey, arrLen; - if (node.params.length) { + if (paramsCount) { // this method has additional params, so we need to subtract // the index of the current argument position from the // position in the array that we want to populate diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/parameters/options.json b/packages/babel-plugin-transform-parameters/test/fixtures/parameters/options.json index 4ee046b12d..4698618caa 100644 --- a/packages/babel-plugin-transform-parameters/test/fixtures/parameters/options.json +++ b/packages/babel-plugin-transform-parameters/test/fixtures/parameters/options.json @@ -2,6 +2,7 @@ "plugins": [ "proposal-class-properties", "external-helpers", + "syntax-typescript", "syntax-flow", "transform-parameters", "transform-block-scoping", diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/parameters/rest-ts-this-parameter/input.js b/packages/babel-plugin-transform-parameters/test/fixtures/parameters/rest-ts-this-parameter/input.js new file mode 100644 index 0000000000..1d2875453e --- /dev/null +++ b/packages/babel-plugin-transform-parameters/test/fixtures/parameters/rest-ts-this-parameter/input.js @@ -0,0 +1,7 @@ +function u(this: Foo, ...items) { + items[0]; +} + +function v(this: Foo, event: string, ...args: any[]) { + args; +} diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/parameters/rest-ts-this-parameter/output.js b/packages/babel-plugin-transform-parameters/test/fixtures/parameters/rest-ts-this-parameter/output.js new file mode 100644 index 0000000000..55822308fd --- /dev/null +++ b/packages/babel-plugin-transform-parameters/test/fixtures/parameters/rest-ts-this-parameter/output.js @@ -0,0 +1,11 @@ +function u(this: Foo) { + arguments.length <= 0 ? undefined : arguments[0]; +} + +function v(this: Foo, event: string) { + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + args; +}