Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix(scope-manager): support rest function type parameters (#2491)
Fixes #2449
  • Loading branch information
bradzacher committed Sep 5, 2020
1 parent 36305df commit 9d8b4c4
Show file tree
Hide file tree
Showing 8 changed files with 310 additions and 1 deletion.
8 changes: 8 additions & 0 deletions packages/eslint-plugin/tests/rules/no-unused-vars.test.ts
Expand Up @@ -767,6 +767,14 @@ export abstract class Foo {
protected abstract readonly type: FooType;
}
`,
// https://github.com/typescript-eslint/typescript-eslint/issues/2449
`
export type F<A extends unknown[]> = (...a: A) => unknown;
`,
`
import { Foo } from './bar';
export type F<A extends unknown[]> = (...a: Foo<A>) => unknown;
`,
],

invalid: [
Expand Down
12 changes: 11 additions & 1 deletion packages/scope-manager/src/referencer/TypeVisitor.ts
Expand Up @@ -33,6 +33,7 @@ class TypeVisitor extends Visitor {
this.visit(node.typeParameters);

for (const param of node.params) {
let didVisitAnnotation = false;
this.visitPattern(param, (pattern, info) => {
// a parameter name creates a value type variable which can be referenced later via typeof arg
this.#referencer
Expand All @@ -41,8 +42,17 @@ class TypeVisitor extends Visitor {
pattern,
new ParameterDefinition(pattern, node, info.rest),
);
this.visit(pattern.typeAnnotation);

if (pattern.typeAnnotation) {
this.visit(pattern.typeAnnotation);
didVisitAnnotation = true;
}
});

// there are a few special cases where the type annotation is owned by the parameter, not the pattern
if (!didVisitAnnotation && 'typeAnnotation' in param) {
this.visit(param.typeAnnotation);
}
}
this.visit(node.returnType);

Expand Down
@@ -0,0 +1 @@
type Fn<A extends unknown[]> = ([a]: A) => unknown;
@@ -0,0 +1,96 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`type-declaration function params array-pattern 1`] = `
ScopeManager {
variables: Array [
Variable$1 {
defs: Array [
TypeDefinition$1 {
name: Identifier<"Fn">,
node: TSTypeAliasDeclaration$1,
},
],
name: "Fn",
references: Array [],
isValueVariable: false,
isTypeVariable: true,
},
Variable$2 {
defs: Array [
TypeDefinition$2 {
name: Identifier<"A">,
node: TSTypeParameter$2,
},
],
name: "A",
references: Array [
Reference$1 {
identifier: Identifier<"A">,
isRead: true,
isTypeReference: true,
isValueReference: false,
isWrite: false,
resolved: Variable$2,
},
],
isValueVariable: false,
isTypeVariable: true,
},
Variable$3 {
defs: Array [
ParameterDefinition$3 {
name: Identifier<"a">,
node: TSFunctionType$3,
},
],
name: "a",
references: Array [],
isValueVariable: true,
isTypeVariable: false,
},
],
scopes: Array [
GlobalScope$1 {
block: Program$4,
isStrict: false,
references: Array [],
set: Map {
"Fn" => Variable$1,
},
type: "global",
upper: null,
variables: Array [
Variable$1,
],
},
TypeScope$2 {
block: TSTypeAliasDeclaration$1,
isStrict: true,
references: Array [],
set: Map {
"A" => Variable$2,
},
type: "type",
upper: GlobalScope$1,
variables: Array [
Variable$2,
],
},
FunctionTypeScope$3 {
block: TSFunctionType$3,
isStrict: true,
references: Array [
Reference$1,
],
set: Map {
"a" => Variable$3,
},
type: "functionType",
upper: TypeScope$2,
variables: Array [
Variable$3,
],
},
],
}
`;
@@ -0,0 +1 @@
type Fn<A extends { a: string }> = ({ a }: A) => unknown;
@@ -0,0 +1,96 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`type-declaration function params object-pattern 1`] = `
ScopeManager {
variables: Array [
Variable$1 {
defs: Array [
TypeDefinition$1 {
name: Identifier<"Fn">,
node: TSTypeAliasDeclaration$1,
},
],
name: "Fn",
references: Array [],
isValueVariable: false,
isTypeVariable: true,
},
Variable$2 {
defs: Array [
TypeDefinition$2 {
name: Identifier<"A">,
node: TSTypeParameter$2,
},
],
name: "A",
references: Array [
Reference$1 {
identifier: Identifier<"A">,
isRead: true,
isTypeReference: true,
isValueReference: false,
isWrite: false,
resolved: Variable$2,
},
],
isValueVariable: false,
isTypeVariable: true,
},
Variable$3 {
defs: Array [
ParameterDefinition$3 {
name: Identifier<"a">,
node: TSFunctionType$3,
},
],
name: "a",
references: Array [],
isValueVariable: true,
isTypeVariable: false,
},
],
scopes: Array [
GlobalScope$1 {
block: Program$4,
isStrict: false,
references: Array [],
set: Map {
"Fn" => Variable$1,
},
type: "global",
upper: null,
variables: Array [
Variable$1,
],
},
TypeScope$2 {
block: TSTypeAliasDeclaration$1,
isStrict: true,
references: Array [],
set: Map {
"A" => Variable$2,
},
type: "type",
upper: GlobalScope$1,
variables: Array [
Variable$2,
],
},
FunctionTypeScope$3 {
block: TSFunctionType$3,
isStrict: true,
references: Array [
Reference$1,
],
set: Map {
"a" => Variable$3,
},
type: "functionType",
upper: TypeScope$2,
variables: Array [
Variable$3,
],
},
],
}
`;
@@ -0,0 +1 @@
type Fn<A extends unknown[]> = (...a: A) => unknown;
@@ -0,0 +1,96 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`type-declaration function params rest-element 1`] = `
ScopeManager {
variables: Array [
Variable$1 {
defs: Array [
TypeDefinition$1 {
name: Identifier<"Fn">,
node: TSTypeAliasDeclaration$1,
},
],
name: "Fn",
references: Array [],
isValueVariable: false,
isTypeVariable: true,
},
Variable$2 {
defs: Array [
TypeDefinition$2 {
name: Identifier<"A">,
node: TSTypeParameter$2,
},
],
name: "A",
references: Array [
Reference$1 {
identifier: Identifier<"A">,
isRead: true,
isTypeReference: true,
isValueReference: false,
isWrite: false,
resolved: Variable$2,
},
],
isValueVariable: false,
isTypeVariable: true,
},
Variable$3 {
defs: Array [
ParameterDefinition$3 {
name: Identifier<"a">,
node: TSFunctionType$3,
},
],
name: "a",
references: Array [],
isValueVariable: true,
isTypeVariable: false,
},
],
scopes: Array [
GlobalScope$1 {
block: Program$4,
isStrict: false,
references: Array [],
set: Map {
"Fn" => Variable$1,
},
type: "global",
upper: null,
variables: Array [
Variable$1,
],
},
TypeScope$2 {
block: TSTypeAliasDeclaration$1,
isStrict: true,
references: Array [],
set: Map {
"A" => Variable$2,
},
type: "type",
upper: GlobalScope$1,
variables: Array [
Variable$2,
],
},
FunctionTypeScope$3 {
block: TSFunctionType$3,
isStrict: true,
references: Array [
Reference$1,
],
set: Map {
"a" => Variable$3,
},
type: "functionType",
upper: TypeScope$2,
variables: Array [
Variable$3,
],
},
],
}
`;

0 comments on commit 9d8b4c4

Please sign in to comment.