From 660bace4c3da569d71cf1e296ac4f6ed35bdfc44 Mon Sep 17 00:00:00 2001 From: Alexander T Date: Wed, 19 Feb 2020 19:21:32 +0200 Subject: [PATCH] fix(eslint-plugin): [typedef] allow array/object destructuring in for/of (#1570) --- packages/eslint-plugin/docs/rules/typedef.md | 6 +++ packages/eslint-plugin/src/rules/typedef.ts | 37 +++++++++++++- .../eslint-plugin/tests/rules/typedef.test.ts | 48 +++++++++++++++++++ 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/typedef.md b/packages/eslint-plugin/docs/rules/typedef.md index eac8472d946..17a57412bc2 100644 --- a/packages/eslint-plugin/docs/rules/typedef.md +++ b/packages/eslint-plugin/docs/rules/typedef.md @@ -76,6 +76,9 @@ Examples of **correct** code with `{ "arrayDestructuring": true }`: const [a]: number[] = [1]; const [b]: [number] = [2]; const [c, d]: [boolean, string] = [true, 'text']; + +for (const [key, val] of new Map([['key', 1]])) { +} ``` ### `arrowParameter` @@ -144,6 +147,9 @@ Examples of **correct** code with `{ "objectDestructuring": true }`: ```ts const { length }: { length: number } = 'text'; const [b, c]: [number, number] = Math.random() ? [1, 2] : [3, 4]; + +for (const { key, val } of [{ key: 'key', val: 1 }]) { +} ``` ### `parameter` diff --git a/packages/eslint-plugin/src/rules/typedef.ts b/packages/eslint-plugin/src/rules/typedef.ts index 19c4244d9f9..dd7bcc29c61 100644 --- a/packages/eslint-plugin/src/rules/typedef.ts +++ b/packages/eslint-plugin/src/rules/typedef.ts @@ -69,6 +69,31 @@ export default util.createRule<[Options], MessageIds>({ return node.type === AST_NODE_TYPES.Identifier ? node.name : undefined; } + function isForOfStatementContext( + node: TSESTree.ArrayPattern | TSESTree.ObjectPattern, + ): boolean { + let current: TSESTree.Node | undefined = node.parent; + while (current) { + switch (current.type) { + case AST_NODE_TYPES.VariableDeclarator: + case AST_NODE_TYPES.VariableDeclaration: + case AST_NODE_TYPES.ObjectPattern: + case AST_NODE_TYPES.ArrayPattern: + case AST_NODE_TYPES.Property: + current = current.parent; + break; + + case AST_NODE_TYPES.ForOfStatement: + return true; + + default: + current = undefined; + } + } + + return false; + } + function checkParameters(params: TSESTree.Parameter[]): void { for (const param of params) { let annotationNode: TSESTree.Node | undefined; @@ -102,7 +127,11 @@ export default util.createRule<[Options], MessageIds>({ return { ArrayPattern(node): void { - if (options[OptionKeys.ArrayDestructuring] && !node.typeAnnotation) { + if ( + options[OptionKeys.ArrayDestructuring] && + !node.typeAnnotation && + !isForOfStatementContext(node) + ) { report(node); } }, @@ -132,7 +161,11 @@ export default util.createRule<[Options], MessageIds>({ } }, ObjectPattern(node): void { - if (options[OptionKeys.ObjectDestructuring] && !node.typeAnnotation) { + if ( + options[OptionKeys.ObjectDestructuring] && + !node.typeAnnotation && + !isForOfStatementContext(node) + ) { report(node); } }, diff --git a/packages/eslint-plugin/tests/rules/typedef.test.ts b/packages/eslint-plugin/tests/rules/typedef.test.ts index c9e35c356eb..679ed1a8a51 100644 --- a/packages/eslint-plugin/tests/rules/typedef.test.ts +++ b/packages/eslint-plugin/tests/rules/typedef.test.ts @@ -38,6 +38,30 @@ ruleTester.run('typedef', rule, { }, ], }, + { + code: `for (const [key, val] of new Map([['key', 1]])) {}`, + options: [ + { + arrayDestructuring: true, + }, + ], + }, + { + code: `for (const [[key]] of [[['key']]]) {}`, + options: [ + { + arrayDestructuring: true, + }, + ], + }, + { + code: `for (const [[{ key }]] of [[[{ key: 'value' }]]]) {}`, + options: [ + { + arrayDestructuring: true, + }, + ], + }, `let a: number; [a] = [1];`, // Arrow parameters @@ -93,6 +117,22 @@ ruleTester.run('typedef', rule, { }, ], }, + { + code: `for (const {p1: {p2: { p3 }}} of [{p1: {p2: {p3: 'value'}}}]) {}`, + options: [ + { + objectDestructuring: true, + }, + ], + }, + { + code: `for (const {p1: {p2: { p3: [key] }}} of [{p1: {p2: {p3: ['value']}}}]) {}`, + options: [ + { + objectDestructuring: true, + }, + ], + }, { code: `const { a } = { a: 1 };`, options: [ @@ -101,6 +141,14 @@ ruleTester.run('typedef', rule, { }, ], }, + { + code: `for (const { key, val } of [{ key: 'key', val: 1 }]) {}`, + options: [ + { + objectDestructuring: true, + }, + ], + }, // Function parameters `function receivesNumber(a: number): void { }`, `function receivesStrings(a: string, b: string): void { }`,