C0ZEN
C0ZEN

Reputation: 934

ESLint with TypeScript and Firebase - no-undef error

I use eslint in my project with typescript-eslint to be able to lint TypeScript code.
I have an issue with an import provided by firebase-admin regarding the no-undef rule.

Environment:

"firebase-admin": "9.4.1"
"eslint": "7.14.0"
"@typescript-eslint/eslint-plugin": "4.8.2"
"@typescript-eslint/parser": "4.8.2"
"typescript": "4.1.2"

Rule:

no-undef:
 - error
 - typeof: true

All rules (.eslintrc):

root: true
env:
  es6: true
  node: true
  jest/globals: true
extends:
  - 'eslint:recommended'
  - google
  - 'plugin:@typescript-eslint/eslint-recommended'
  - 'plugin:@typescript-eslint/recommended'
  - 'plugin:@typescript-eslint/recommended-requiring-type-checking'
  - 'plugin:import/errors'
  - 'plugin:import/warnings'
  - 'plugin:import/typescript'
  - 'plugin:jest/style'
  - 'plugin:jest/all'
  - 'plugin:jsdoc/recommended'
  - 'plugin:prettier/recommended'
globals:
  Atomics: readonly
  SharedArrayBuffer: readonly
parserOptions:
  ecmaVersion: 2018
  sourceType: module
  project: ./tsconfig.json
parser: '@typescript-eslint/parser'
plugins:
  - '@typescript-eslint'
  - typescript-sort-keys
  - jest
  - prettier
  - progress
  - jsdoc
settings:
  import/extensions:
    - .js
    - .ts
  import/parsers:
    '@typescript-eslint/parser':
      - .ts
  import/cache:
    lifetime: Infinity
rules:
  progress/activate: 1
  jest/no-done-callback: error
  jest/no-disabled-tests: off
  '@typescript-eslint/member-ordering':
    - error
    - default:
        - signature
        - public-static-field
        - protected-static-field
        - private-static-field
        - public-static-method
        - protected-static-method
        - private-static-method
        - public-abstract-field
        - protected-abstract-field
        - private-abstract-field
        - public-instance-field
        - protected-instance-field
        - private-instance-field
        - public-constructor
        - protected-constructor
        - private-constructor
        - public-instance-method
        - protected-instance-method
        - private-instance-method
        - public-abstract-method
        - protected-abstract-method
        - private-abstract-method
  jest/lowercase-name:
    - error
    - ignore:
        - describe
  jest/no-hooks:
    - error
    - allow:
        - beforeAll
        - beforeEach
        - afterAll
        - afterEach
  typescript-sort-keys/interface:
    - error
    - asc
    - caseSensitive: true
      natural: true
  typescript-sort-keys/string-enum:
    - error
    - asc
    - caseSensitive: true
      natural: true
  quotes: off
  no-else-return:
    - error
    - allowElseIf: true
  sort-keys:
    - error
    - asc
    - caseSensitive: true
      natural: true
      minKeys: 2
  '@typescript-eslint/quotes':
    - error
    - backtick
  '@typescript-eslint/no-var-requires': off
  '@typescript-eslint/explicit-function-return-type': off
  '@typescript-eslint/no-unused-vars':
    - error
    - argsIgnorePattern: ^_
  import/no-namespace: off
  import/first: error
  import/exports-last: error
  import/no-duplicates: error
  import/no-commonjs: error
  import/no-dynamic-require: error
  import/order:
    - error
    - groups:
      - index
      - sibling
      - parent
      - internal
      - external
      - builtin
      - object
      newlines-between: never
      alphabetize:
        order: asc
        caseInsensitive: false
  indent: off
  no-duplicate-imports: error
  sort-imports: off
  new-cap:
    - error
    - capIsNewExceptions:
      - StoreConfig
  '@typescript-eslint/naming-convention':
    - error
    - selector: default
      format:
        - camelCase
    - selector: variable
      format:
        - camelCase
        - UPPER_CASE
    - selector: variable
      types:
        - boolean
      format:
        - PascalCase
        - UPPER_CASE
      prefix:
        - is
        - has
        - should
        - contains
        - as
        - to
    - selector: parameter
      format:
        - camelCase
      leadingUnderscore: allow
    - selector: parameter
      types:
        - boolean
      format:
        - PascalCase
      leadingUnderscore: allow
      prefix:
        - is
        - has
        - should
        - contains
        - as
        - to
    - selector: function
      format:
        - camelCase
    - selector: memberLike
      modifiers:
        - private
      format:
        - camelCase
      leadingUnderscore: require
    - selector: memberLike
      modifiers:
        - protected
      format:
        - camelCase
      leadingUnderscore: require
    - selector: typeLike
      format:
        - PascalCase
    - selector: typeParameter
      format:
        - PascalCase
      prefix:
        - T
    - selector: interface
      format:
        - PascalCase
      prefix:
        - I
    - selector: typeAlias
      format:
        - PascalCase
      prefix:
        - I
    - selector: enumMember
      format:
        - UPPER_CASE
    - selector: enum
      format:
        - PascalCase
      suffix:
        - Enum
  '@typescript-eslint/no-explicit-any':
    - error
    - fixToUnknown: false
      ignoreRestArgs: false
  object-curly-spacing:
    - error
    - always
  linebreak-style: off
  computed-property-spacing:
    - error
    - never
  array-bracket-spacing: off
  prefer-rest-params: off
  require-jsdoc: off
  max-len: off
  comma-dangle: off
  object-shorthand:
    - error
    - always
    - avoidExplicitReturnArrows: true
  arrow-body-style:
    - error
    - as-needed
    - requireReturnForObjectLiteral: true
  no-dupe-else-if: error
  no-unmodified-loop-condition: error
  no-eval: error
  no-extra-label: error
  no-await-in-loop: error
  prefer-destructuring:
    - error
    - VariableDeclarator:
        array: true
        object: true
      AssignmentExpression:
        array: true
        object: true
    - enforceForRenamedProperties: false
  '@typescript-eslint/unbound-method': off
  '@typescript-eslint/no-unsafe-call': off
  '@typescript-eslint/no-unsafe-member-access': off
  '@typescript-eslint/no-unsafe-return': off
  '@typescript-eslint/no-unsafe-assignment': off
  '@typescript-eslint/prefer-enum-initializers': error
  '@typescript-eslint/prefer-literal-enum-member': off
  '@typescript-eslint/unified-signatures': error
  '@typescript-eslint/ban-ts-comment': error
  no-undef-init: error
  no-magic-numbers:
    - error
    - enforceConst: true
      detectObjects: false
  prettier/prettier:
    - error
    - printWidth: 120
      useTabs: false
      semi: true
      singleQuote: true
      quoteProps: consistent
      trailingComma: es5
      bracketSpacing: true
      arrowParens: always
      endOfLine: lf
      tabWidth: 2
  import/no-unresolved: error
  prefer-template: error
  no-useless-concat: error
  no-constant-condition:
    - error
    - checkLoops: true
  prefer-promise-reject-errors:
    - error
    - allowEmptyReject: false
  no-case-declarations: error
  no-irregular-whitespace:
    - error
    - skipStrings: false
      skipComments: false
      skipRegExps: false
      skipTemplates: false
  '@typescript-eslint/adjacent-overload-signatures': error
  '@typescript-eslint/no-misused-promises':
    - error
    - checksConditionals: true
      checksVoidReturn: true
  no-invalid-this: off
  '@typescript-eslint/no-invalid-this': error
  prefer-const:
    - error
    - destructuring: any
      ignoreReadBeforeAssign: false
  camelcase: off
  valid-jsdoc: off
  'jsdoc/require-jsdoc': warn # @todo change it to error but we should fix all current jsdoc errors
  curly:
    - error
    - all
  '@typescript-eslint/prefer-regexp-exec': error
  '@typescript-eslint/await-thenable': error
  '@typescript-eslint/prefer-readonly': error
  '@typescript-eslint/triple-slash-reference':
    - error
    - path: never
      types: never
      lib: never
  '@typescript-eslint/prefer-readonly-parameter-types': # @todo change it to error once the nested object issue was resolved (https://github.com/typescript-eslint/typescript-eslint/issues/2823)
    - warn
    - ignoreInferredTypes: true
      checkParameterProperties: false
  '@typescript-eslint/no-empty-interface':
    - error
    - allowSingleExtends: false
  '@typescript-eslint/restrict-template-expressions':
    - error
    - allowNumber: false
      allowBoolean: false
      allowAny: false
      allowNullish: false
  '@typescript-eslint/ban-types': error
  '@typescript-eslint/restrict-plus-operands':
    - error
    - checkCompoundAssignments: true
  '@typescript-eslint/no-floating-promises':
    - error
    - ignoreVoid: true
  no-undef:
    - warn # @todo change it to error 
    - typeof: true
  no-useless-escape: error
  no-prototype-builtins: error
  require-await: off
  '@typescript-eslint/require-await': error
  no-empty-function: off
  no-var: error
  spaced-comment:
    - error
    - always
    - markers:
        - /
  '@typescript-eslint/no-empty-function':
    - error
    - allow:
        - decoratedFunctions
overrides:
  - files:
      - '*.js'
    rules:
      '@typescript-eslint/explicit-module-boundary-types': off
      import/no-commonjs: off
  - files:
      - '*.ts'
    rules:
      '@typescript-eslint/explicit-function-return-type':
        - error
        - allowExpressions: false
          allowTypedFunctionExpressions: false
          allowHigherOrderFunctions: false
      '@typescript-eslint/no-var-requires': error
  - files:
      - '*.spec.ts'
    rules:
      no-magic-numbers: off
      '@typescript-eslint/ban-types':
        - error
        - types:
            Readonly:
              message: 'Sonia rule - This is useless inside the tests'
          extendDefaults: true
      '@typescript-eslint/naming-convention':
        - error
        - selector: default
          format:
            - camelCase
        - selector: variable
          format:
            - camelCase
            - UPPER_CASE
        - selector: variable
          types:
            - boolean
          format:
            - camelCase
            - UPPER_CASE
        - selector: parameter
          format:
            - camelCase
          leadingUnderscore: allow
        - selector: parameter
          types:
            - boolean
          format:
            - camelCase
          leadingUnderscore: allow
        - selector: function
          format:
            - camelCase
        - selector: memberLike
          modifiers:
            - private
          format:
            - camelCase
          leadingUnderscore: require
        - selector: memberLike
          modifiers:
            - protected
          format:
            - camelCase
          leadingUnderscore: require
        - selector: typeLike
          format:
            - PascalCase
        - selector: typeParameter
          format:
            - PascalCase
          prefix:
            - T
        - selector: interface
          format:
            - PascalCase
          prefix:
            - I
        - selector: typeAlias
          format:
            - PascalCase
          prefix:
            - I
        - selector: enumMember
          format:
            - UPPER_CASE
        - selector: enum
          format:
            - PascalCase
          suffix:
            - Enum
      '@typescript-eslint/no-explicit-any': off
      '@typescript-eslint/ban-ts-comment': off

Failing import based only on the no-undef rule:

import admin from 'firebase-admin';
import WriteResult = admin.firestore.WriteResult;

Error:

ESLint: 'firestore' is not defined.(no-undef)

Yet my project is working and this is valid for TypeScript.

Based on the documentation of TypeScript ESLint, using globals or env can be the best workaround.
Except I did not find any related information about an existing configuration so I am stuck.

Do you have any solution? Thanks.

Upvotes: 0

Views: 9047

Answers (2)

Anjan Talatam
Anjan Talatam

Reputation: 3996

This helped me in my React-Typescript project

Add this to your .eslintrc.json

  "overrides": [
    {
      "files": ["*.ts", "*.tsx"],
      "rules": {
        "no-undef": "off"
      }
    }
  ]

if you are using .eslitrc.js do this

overrides: [
    {
      files: ['*.ts', '*.tsx'],
      rules: {
        'no-undef': 'off',
      },
    },
  ],

Upvotes: 1

Abdelrahman Abounegm
Abdelrahman Abounegm

Reputation: 715

I believe you have already linked to the recommended answer: disabling the no-undef rule. To quote the documentation page you linked:

We strongly recommend that you do not use the no-undef lint rule on TypeScript projects. The checks it provides are already provided by TypeScript without the need for configuration - TypeScript just does this significantly better.

And if you have a mix of TypeScript and JavaScript in your project, it is better to disable it for TypeScript files only:

overrides:
  - files: 
    - "*.ts"
    rules:
      'no-undef': off

However, if you still prefer to keep the rule on and want to silence the error for a few particular global variables (firestore in your case), you can follow the ESLint configuration guide for specifying globals, which lists 2 methods:

  1. Configuration comments: add /* global firestore */ at the top of your file
  2. Configuration file: add the following to your .eslintrc:
globals:
  firestore: readonly

Upvotes: 6

Related Questions