Search code examples
node.jseslintts-jesttypescript-eslint

ESLint integration with Typescript


I'm on a project to upgrade the versions of an older AWS CDK typescript app. It uses integrated Jest+ESLint as a local "test" before deployment and integration testing in AWS.

The ESLint 8.0 documentation has a tutorial for integrating node, but not typescript, and following the basic ESLint migration guide doesn't get it working.

The original test code (before going through the ESLint 8.0 migration guide):

const { CLIEngine } = require('eslint');
import path from 'path';

// Import config from eslintrc.
const cli = new CLIEngine({
  configFile: path.resolve(__dirname, '../.eslintrc'),
  useEslintrc: false,
  ignore: false,
});

// Path to file to test
const filePath = path.resolve(__dirname, '../lib/stack.ts');
const report = cli.executeOnFiles([filePath]);

const formatter = cli.getFormatter();

// Print detailed linting results only if there are errors or warnings.
if (report.errorCount > 0 || report.warningCount > 0) {
  console.log(formatter(report.results));
} else {
    console.log('No errors or warnings found in linting results');
}

console.log(`Found ${report.errorCount} errors and ${report.warningCount} warnings`);

test('Lint test on stack.ts', () => {
    // If there are any errors, fail the test.
    expect(report.errorCount).toBe(0);
});

Based on the 8.0 migration guide I changed it to the following:

const { ESLint } = require('eslint');
import path from 'path';

// Import config from eslintrc.
const cli = new ESLint({
  overrideConfigFile: path.resolve(__dirname, '../.eslintrc'),
  useEslintrc: false,
  ignore: false,
});

// Path to file to test
const filePath = path.resolve(__dirname, '../lib/stack.ts');
const report = cli.lintFiles([filePath]);

const formatter = cli.loadFormatter();

// Print detailed linting results only if there are errors or warnings.
if (report.errorCount > 0 || report.warningCount > 0) {
  console.log(formatter(report.results));
} else {
  console.log('No errors or warnings found in linting results');
}

console.log(`Found ${report.errorCount} errors and ${report.warningCount} warnings`);

test('Lint test on stack.ts', () => {
    // If there are any errors, fail the test.
    expect(report.errorCount).toBe(0);
});

When I run the tests I get:

node:internal/process/promises:288
  triggerUncaughtException(err, true /* fromPromise */);
                ^
AssertionError [ERR_ASSERTION]: Node must be provided when reporting error if location is not provided
...stacktrace can be provided if helpful

When I print out the report object I see that lintFiles() returns an unresolved Promise. I imagine that's because I'm trying to use node in a typescript context. Is it possible to integrate ESLint 8 with typescript? With what syntax?

If it exists somewhere, something like this integration tutorial for node (except for typescript instead) would be pie-in-the-sky perfect:

My versions:

$ npm list
├── @jest/globals@29.7.0
├── @types/eslint@8.56.2
├── @types/jest@29.5.11
├── @types/node@18.0.6
├── @typescript-eslint/eslint-plugin@6.20.0
├── @typescript-eslint/parser@6.20.0
├── aws-cdk-lib@2.124.0
├── eslint-plugin-jest@27.6.3
├── eslint@8.56.0
├── jest-html-reporters@3.1.7
├── jest-junit@16.0.0
├── jest@29.7.0
├── node@18.18.2
├── ts-jest@29.1.2
└── ts-node@10.9.2

The .eslintrc:

    {
    "env": {
        "jest/globals": true
    },
    "extends": [
        "eslint:recommended"
    ],
    "rules": {
    },
    "parserOptions": {
        "ecmaVersion": "ES2021",
        "sourceType": "module",
        "project": "./tsconfig.json"

    },
    "parser": "@typescript-eslint/parser",
    "plugins": [
      "@typescript-eslint",
      "jest", 
      "eslint-plugin-jest"
    ],
}

Solution

  • Rather than continue with ESLint, I've converted the application to use CDK Assertions as described in the AWS documentation.

    This actually looks at the CloudFormation Template being produced by the application and allows you to test against that.

    I'm pretty sure ESLint was not meant to be used in the way that it was being used in the codebase and I'm glad to be rid of it!