Various performance baselines for typescript-eslint.
You'll need hyperfine installed locally, such as with brew install hyperfine or winget install hyperfine.
See sharkdp/hyperfine#installation.
npm install
npm run generate
npm run measureTo measure a local typescript-eslint build rather than the published one, point TYPESCRIPT_ESLINT_PATH at the checkout.
TYPESCRIPT_ESLINT_PATH=$(realpath ../typescript-eslint) npm run generate
TYPESCRIPT_ESLINT_PATH=$(realpath ../typescript-eslint) npm run measuregenerate and measure take an optional comparison type, defined in comparisons in src/data.ts:
default:parserOptions.projectagainstparserOptions.projectService, plus the native backend whenTYPESCRIPT_ESLINT_PATHis setnative: the classic project service against the TypeScript 7.1 native backend, across file counts and rule sets
TYPESCRIPT_ESLINT_PATH=$(realpath ../typescript-eslint) npm run generate:native
TYPESCRIPT_ESLINT_PATH=$(realpath ../typescript-eslint) npm run measure:nativeThe native backend is unpublished, so the native comparison requires TYPESCRIPT_ESLINT_PATH.
You can manually measure individual cases by running hyperfine ../../node_modules/eslint/bin/eslint.js --ignore-failure --warmup 1.
Each comparison in src/data.ts can be modified to test:
files: roughly how many generated files should be linted- Files repeat a pattern of two each: super simple, relatively simple, using generics, using result unions, and using all of those plus fancier types
layout: what rough shape of imports those files exhibit:"even": a single root-levelindex.tsimporting from roughly an even triangle shape of files"references": a single root-leveltsconfig.jsonwith project references to a few projects"wide": one root-levelindex.tsimporting from all files in the project
rules: which rules are enabled:"floating": only@typescript-eslint/no-floating-promises"recommended":recommendedTypeChecked, which queries type information far more often
singleRun: whether to enable single-run inference as a performance boosttypes: how type information is obtained for typed linting:"project":parserOptions.project"service":parserOptions.projectService"native":parserOptions.projectServicewith the experimental TypeScript 7.1 native backend
Right now, parserOptions.project outperforms parserOptions.projectService, by roughly 7%.
This is a performance issue and we are investigating it as a bug.
┌───────┬───────────────┬───────────────────────┬───────────────────────┐
│ files │ rules │ project (even layout) │ service (even layout) │
├───────┼───────────────┼───────────────────────┼───────────────────────┤
│ 1024 │ 'recommended' │ '6.895 s ± 0.038 s' │ '7.356 s ± 0.045 s' │
└───────┴───────────────┴───────────────────────┴───────────────────────┘
See typescript-eslint/typescript-eslint#9571 Performance: parserOptions.projectService no longer outperforms parserOptions.project in typescript-eslint.
- Example measurements taken on an M1 Max Mac Studio with Node.js 24.15.0, TypeScript 6.0.3, and typescript-eslint 8.70.0
- Single-run inference is enabled for both types
The comparisons/ directory contains details on more specific comparisons.
See each comparisons/*.md file for details on what's being measured.
The traces/ directory contains more specific traces for investigations.
✨ You might consider using 0x for nice flamegraph visuals.
All comparisons were run on a common shape of linting: 1024 files with the "even" (triangle-shaped) imports layout.
Jake Bailey 🤔 |
Josh Goldberg ✨ 🤔 🚇 🚧 📆 🔧 |