Skip to content

Commit

Permalink
fix(eslint-plugin): [typedef] allow array/object destructuring in for…
Browse files Browse the repository at this point in the history
…/of (#1570)
  • Loading branch information
a-tarasyuk committed Feb 19, 2020
1 parent 0d8e87e commit 660bace
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 2 deletions.
6 changes: 6 additions & 0 deletions packages/eslint-plugin/docs/rules/typedef.md
Expand Up @@ -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`
Expand Down Expand Up @@ -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`
Expand Down
37 changes: 35 additions & 2 deletions packages/eslint-plugin/src/rules/typedef.ts
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
},
Expand Down Expand Up @@ -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);
}
},
Expand Down
48 changes: 48 additions & 0 deletions packages/eslint-plugin/tests/rules/typedef.test.ts
Expand Up @@ -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
Expand Down Expand Up @@ -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: [
Expand All @@ -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 { }`,
Expand Down

0 comments on commit 660bace

Please sign in to comment.