Skip to content
Permalink
Browse files

fix(scope-manager): support type predicates (#2493)

Fixes #2462
  • Loading branch information
bradzacher committed Sep 5, 2020
1 parent a2686c0 commit a40f54c39d59096a0d12a492807dcd52fbcdc384
Showing with 1,292 additions and 0 deletions.
  1. +29 −0 packages/eslint-plugin/tests/eslint-rules/no-undef.test.ts
  2. +7 −0 packages/scope-manager/src/referencer/TypeVisitor.ts
  3. +1 −0 packages/scope-manager/tests/fixtures/functions/arrow/type-predicate-asserts1.ts
  4. +84 −0 packages/scope-manager/tests/fixtures/functions/arrow/type-predicate-asserts1.ts.shot
  5. +2 −0 packages/scope-manager/tests/fixtures/functions/arrow/type-predicate-asserts2.ts
  6. +108 −0 packages/scope-manager/tests/fixtures/functions/arrow/type-predicate-asserts2.ts.shot
  7. +3 −0 packages/scope-manager/tests/fixtures/functions/arrow/type-predicate1.ts
  8. +93 −0 packages/scope-manager/tests/fixtures/functions/arrow/type-predicate1.ts.shot
  9. +4 −0 packages/scope-manager/tests/fixtures/functions/arrow/type-predicate2.ts
  10. +117 −0 packages/scope-manager/tests/fixtures/functions/arrow/type-predicate2.ts.shot
  11. +1 −0 packages/scope-manager/tests/fixtures/functions/function-declaration/type-predicate-asserts1.ts
  12. +80 −0 packages/scope-manager/tests/fixtures/functions/function-declaration/type-predicate-asserts1.ts.shot
  13. +2 −0 packages/scope-manager/tests/fixtures/functions/function-declaration/type-predicate-asserts2.ts
  14. +104 −0 packages/scope-manager/tests/fixtures/functions/function-declaration/type-predicate-asserts2.ts.shot
  15. +3 −0 packages/scope-manager/tests/fixtures/functions/function-declaration/type-predicate1.ts
  16. +89 −0 packages/scope-manager/tests/fixtures/functions/function-declaration/type-predicate1.ts.shot
  17. +4 −0 packages/scope-manager/tests/fixtures/functions/function-declaration/type-predicate2.ts
  18. +113 −0 packages/scope-manager/tests/fixtures/functions/function-declaration/type-predicate2.ts.shot
  19. +1 −0 packages/scope-manager/tests/fixtures/functions/function-expression/type-predicate-asserts1.ts
  20. +93 −0 packages/scope-manager/tests/fixtures/functions/function-expression/type-predicate-asserts1.ts.shot
  21. +2 −0 packages/scope-manager/tests/fixtures/functions/function-expression/type-predicate-asserts2.ts
  22. +117 −0 packages/scope-manager/tests/fixtures/functions/function-expression/type-predicate-asserts2.ts.shot
  23. +3 −0 packages/scope-manager/tests/fixtures/functions/function-expression/type-predicate1.ts
  24. +102 −0 packages/scope-manager/tests/fixtures/functions/function-expression/type-predicate1.ts.shot
  25. +4 −0 packages/scope-manager/tests/fixtures/functions/function-expression/type-predicate2.ts
  26. +126 −0 packages/scope-manager/tests/fixtures/functions/function-expression/type-predicate2.ts.shot
@@ -111,6 +111,35 @@ function eachr<Key, Value>(subject: Map<Key, Value>): typeof subject;
var a = { b: () => {} };
a?.b();
`,
// https://github.com/typescript-eslint/typescript-eslint/issues/2462
`
export default class Column {
isColumnString(column: unknown): column is string {
return typeof this.column === 'string';
}
}
`,
`
type T = string;
function predicate(arg: any): arg is T {
return typeof arg === 'string';
}
`,
`
function predicate(arg: any): asserts arg {
if (arg == null) {
throw 'oops';
}
}
`,
`
type T = string;
function predicate(arg: any): asserts arg is T {
if (typeof arg !== 'string') {
throw 'oops';
}
}
`,
],
invalid: [
{
@@ -199,6 +199,13 @@ class TypeVisitor extends Visitor {
this.visit(node.default);
}

protected TSTypePredicate(node: TSESTree.TSTypePredicate): void {
if (node.parameterName.type !== AST_NODE_TYPES.TSThisType) {
this.#referencer.currentScope().referenceValue(node.parameterName);
}
this.visit(node.typeAnnotation);
}

// a type query `typeof foo` is a special case that references a _non-type_ variable,
protected TSTypeQuery(node: TSESTree.TSTypeQuery): void {
if (node.exprName.type === AST_NODE_TYPES.Identifier) {
@@ -0,0 +1 @@
const foo = (arg: any): asserts arg => {};
@@ -0,0 +1,84 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`functions arrow type-predicate-asserts1 1`] = `
ScopeManager {
variables: Array [
Variable$1 {
defs: Array [
VariableDefinition$1 {
name: Identifier<"foo">,
node: VariableDeclarator$1,
},
],
name: "foo",
references: Array [
Reference$1 {
identifier: Identifier<"foo">,
init: true,
isRead: false,
isTypeReference: false,
isValueReference: true,
isWrite: true,
resolved: Variable$1,
writeExpr: ArrowFunctionExpression$2,
},
],
isValueVariable: true,
isTypeVariable: false,
},
Variable$2 {
defs: Array [
ParameterDefinition$2 {
name: Identifier<"arg">,
node: ArrowFunctionExpression$2,
},
],
name: "arg",
references: Array [
Reference$2 {
identifier: Identifier<"arg">,
isRead: true,
isTypeReference: false,
isValueReference: true,
isWrite: false,
resolved: Variable$2,
},
],
isValueVariable: true,
isTypeVariable: false,
},
],
scopes: Array [
GlobalScope$1 {
block: Program$3,
isStrict: false,
references: Array [
Reference$1,
],
set: Map {
"foo" => Variable$1,
},
type: "global",
upper: null,
variables: Array [
Variable$1,
],
},
FunctionScope$2 {
block: ArrowFunctionExpression$2,
isStrict: false,
references: Array [
Reference$2,
],
set: Map {
"arg" => Variable$2,
},
type: "function",
upper: GlobalScope$1,
variables: Array [
Variable$2,
],
},
],
}
`;
@@ -0,0 +1,2 @@
type T = string;
const foo = (arg: any): asserts arg is T => {};
@@ -0,0 +1,108 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`functions arrow type-predicate-asserts2 1`] = `
ScopeManager {
variables: Array [
Variable$1 {
defs: Array [
TypeDefinition$1 {
name: Identifier<"T">,
node: TSTypeAliasDeclaration$1,
},
],
name: "T",
references: Array [
Reference$3 {
identifier: Identifier<"T">,
isRead: true,
isTypeReference: true,
isValueReference: false,
isWrite: false,
resolved: Variable$1,
},
],
isValueVariable: false,
isTypeVariable: true,
},
Variable$2 {
defs: Array [
VariableDefinition$2 {
name: Identifier<"foo">,
node: VariableDeclarator$2,
},
],
name: "foo",
references: Array [
Reference$1 {
identifier: Identifier<"foo">,
init: true,
isRead: false,
isTypeReference: false,
isValueReference: true,
isWrite: true,
resolved: Variable$2,
writeExpr: ArrowFunctionExpression$3,
},
],
isValueVariable: true,
isTypeVariable: false,
},
Variable$3 {
defs: Array [
ParameterDefinition$3 {
name: Identifier<"arg">,
node: ArrowFunctionExpression$3,
},
],
name: "arg",
references: Array [
Reference$2 {
identifier: Identifier<"arg">,
isRead: true,
isTypeReference: false,
isValueReference: true,
isWrite: false,
resolved: Variable$3,
},
],
isValueVariable: true,
isTypeVariable: false,
},
],
scopes: Array [
GlobalScope$1 {
block: Program$4,
isStrict: false,
references: Array [
Reference$1,
],
set: Map {
"T" => Variable$1,
"foo" => Variable$2,
},
type: "global",
upper: null,
variables: Array [
Variable$1,
Variable$2,
],
},
FunctionScope$2 {
block: ArrowFunctionExpression$3,
isStrict: false,
references: Array [
Reference$2,
Reference$3,
],
set: Map {
"arg" => Variable$3,
},
type: "function",
upper: GlobalScope$1,
variables: Array [
Variable$3,
],
},
],
}
`;
@@ -0,0 +1,3 @@
const foo = (arg: any): arg is string => {
return typeof arg === 'string';
};
@@ -0,0 +1,93 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`functions arrow type-predicate1 1`] = `
ScopeManager {
variables: Array [
Variable$1 {
defs: Array [
VariableDefinition$1 {
name: Identifier<"foo">,
node: VariableDeclarator$1,
},
],
name: "foo",
references: Array [
Reference$1 {
identifier: Identifier<"foo">,
init: true,
isRead: false,
isTypeReference: false,
isValueReference: true,
isWrite: true,
resolved: Variable$1,
writeExpr: ArrowFunctionExpression$2,
},
],
isValueVariable: true,
isTypeVariable: false,
},
Variable$2 {
defs: Array [
ParameterDefinition$2 {
name: Identifier<"arg">,
node: ArrowFunctionExpression$2,
},
],
name: "arg",
references: Array [
Reference$2 {
identifier: Identifier<"arg">,
isRead: true,
isTypeReference: false,
isValueReference: true,
isWrite: false,
resolved: Variable$2,
},
Reference$3 {
identifier: Identifier<"arg">,
isRead: true,
isTypeReference: false,
isValueReference: true,
isWrite: false,
resolved: Variable$2,
},
],
isValueVariable: true,
isTypeVariable: false,
},
],
scopes: Array [
GlobalScope$1 {
block: Program$3,
isStrict: false,
references: Array [
Reference$1,
],
set: Map {
"foo" => Variable$1,
},
type: "global",
upper: null,
variables: Array [
Variable$1,
],
},
FunctionScope$2 {
block: ArrowFunctionExpression$2,
isStrict: false,
references: Array [
Reference$2,
Reference$3,
],
set: Map {
"arg" => Variable$2,
},
type: "function",
upper: GlobalScope$1,
variables: Array [
Variable$2,
],
},
],
}
`;
@@ -0,0 +1,4 @@
type T = string;
const foo = (arg: any): arg is T => {
return typeof arg === 'string';
};

0 comments on commit a40f54c

Please sign in to comment.