diff --git a/.eslintrc.js b/.eslintrc.js index 8b4cfa2db36a..2c69c6ecfedf 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -32,6 +32,16 @@ module.exports = { // our plugin :D // + '@typescript-eslint/ban-ts-comment': [ + 'error', + { + 'ts-expect-error': 'allow-with-description', + 'ts-ignore': true, + 'ts-nocheck': true, + 'ts-check': false, + minimumDescriptionLength: 5, + }, + ], '@typescript-eslint/consistent-type-definitions': ['error', 'interface'], '@typescript-eslint/explicit-function-return-type': 'error', '@typescript-eslint/explicit-module-boundary-types': 'off', diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 8ba7451b3889..c1b56bc9f0d8 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -43,6 +43,7 @@ }, "dependencies": { "@typescript-eslint/experimental-utils": "3.3.0", + "debug": "^4.1.1", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.0.0", "semver": "^7.3.2", diff --git a/packages/eslint-plugin/src/rules/await-thenable.ts b/packages/eslint-plugin/src/rules/await-thenable.ts index 78b7ad129393..9858bad8ba2a 100644 --- a/packages/eslint-plugin/src/rules/await-thenable.ts +++ b/packages/eslint-plugin/src/rules/await-thenable.ts @@ -1,5 +1,4 @@ import * as tsutils from 'tsutils'; -import * as ts from 'typescript'; import * as util from '../util'; @@ -30,8 +29,8 @@ export default util.createRule({ const type = checker.getTypeAtLocation(originalNode.expression); if ( - !tsutils.isTypeFlagSet(type, ts.TypeFlags.Any) && - !tsutils.isTypeFlagSet(type, ts.TypeFlags.Unknown) && + !util.isTypeAnyType(type) && + !util.isTypeUnknownType(type) && !tsutils.isThenableType(checker, originalNode.expression, type) ) { context.report({ diff --git a/packages/eslint-plugin/src/rules/no-throw-literal.ts b/packages/eslint-plugin/src/rules/no-throw-literal.ts index b85e0cc742db..67ba9e52ebe5 100644 --- a/packages/eslint-plugin/src/rules/no-throw-literal.ts +++ b/packages/eslint-plugin/src/rules/no-throw-literal.ts @@ -110,7 +110,8 @@ export default util.createRule({ } if ( - type.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown) || + util.isTypeAnyType(type) || + util.isTypeUnknownType(type) || isErrorLike(type) ) { return; diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts b/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts index bed2ac82e55d..1147957a20cb 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts @@ -22,6 +22,8 @@ import { NullThrowsReasons, isMemberOrOptionalMemberExpression, isIdentifier, + isTypeAnyType, + isTypeUnknownType, } from '../util'; // Truthiness utilities @@ -181,13 +183,11 @@ export default createRule({ // Conditional is always necessary if it involves: // `any` or `unknown` or a naked type parameter if ( - unionTypeParts(type).some(part => - isTypeFlagSet( - part, - ts.TypeFlags.Any | - ts.TypeFlags.Unknown | - ts.TypeFlags.TypeParameter, - ), + unionTypeParts(type).some( + part => + isTypeAnyType(part) || + isTypeUnknownType(part) || + isTypeFlagSet(part, ts.TypeFlags.TypeParameter), ) ) { return; @@ -214,7 +214,7 @@ export default createRule({ } const type = getNodeType(node); // Conditional is always necessary if it involves `any` or `unknown` - if (isTypeFlagSet(type, ts.TypeFlags.Any | ts.TypeFlags.Unknown)) { + if (isTypeAnyType(type) || isTypeUnknownType(type)) { return; } const messageId = isTypeFlagSet(type, ts.TypeFlags.Never) @@ -469,8 +469,8 @@ export default createRule({ ? !isNullableOriginFromPrev(node) : true; return ( - isTypeFlagSet(type, ts.TypeFlags.Any) || - isTypeFlagSet(type, ts.TypeFlags.Unknown) || + isTypeAnyType(type) || + isTypeUnknownType(type) || (isNullableType(type, { allowUndefined: true }) && isOwnNullable) ); } diff --git a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts index a3cbb0b6f3bf..a4756266ffca 100644 --- a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts +++ b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts @@ -72,7 +72,7 @@ export default util.createRule({ return true; } - if (options.allowAny && util.isTypeFlagSet(type, ts.TypeFlags.Any)) { + if (options.allowAny && util.isTypeAnyType(type)) { return true; } diff --git a/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts b/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts index df2b59e12ec8..747cbefb7ebe 100644 --- a/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts +++ b/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts @@ -325,8 +325,8 @@ export default util.createRule({ } if ( - types.some(type => - tsutils.isTypeFlagSet(type, ts.TypeFlags.Any | ts.TypeFlags.Unknown), + types.some( + type => util.isTypeAnyType(type) || util.isTypeUnknownType(type), ) ) { variantTypes.add('any'); diff --git a/packages/eslint-plugin/src/util/types.ts b/packages/eslint-plugin/src/util/types.ts index 08a67cd7e5d9..2bd7e1997392 100644 --- a/packages/eslint-plugin/src/util/types.ts +++ b/packages/eslint-plugin/src/util/types.ts @@ -1,3 +1,4 @@ +import debug from 'debug'; import { isCallExpression, isJsxExpression, @@ -13,6 +14,8 @@ import { } from 'tsutils'; import * as ts from 'typescript'; +const log = debug('typescript-eslint:eslint-plugin:utils:types'); + /** * Checks if the given type is either an array type, * or a union made up solely of array types. @@ -326,11 +329,24 @@ export function getTypeArguments( return type.typeArguments ?? []; } +/** + * @returns true if the type is `unknown` + */ +export function isTypeUnknownType(type: ts.Type): boolean { + return isTypeFlagSet(type, ts.TypeFlags.Unknown); +} + /** * @returns true if the type is `any` */ export function isTypeAnyType(type: ts.Type): boolean { - return isTypeFlagSet(type, ts.TypeFlags.Any); + if (isTypeFlagSet(type, ts.TypeFlags.Any)) { + if (type.intrinsicName === 'error') { + log('Found an "error" any type'); + } + return true; + } + return false; } /** diff --git a/packages/eslint-plugin/typings/typescript.d.ts b/packages/eslint-plugin/typings/typescript.d.ts index 7c9089158b4b..73304155ee74 100644 --- a/packages/eslint-plugin/typings/typescript.d.ts +++ b/packages/eslint-plugin/typings/typescript.d.ts @@ -23,4 +23,11 @@ declare module 'typescript' { */ getTypeOfPropertyOfType(type: Type, propertyName: string): Type | undefined; } + + interface Type { + /** + * If the type is `any`, and this is set to "error", then TS was unable to resolve the type + */ + intrinsicName?: string; + } }