Open-source project
palantir/tslint-react avatar
palantir/tslint-react

tslint-react: JSX lint rules for TSLint, and what its version numbers tell you

:orange_book: Lint rules related to React & JSX for TSLint.

752 stars75 forksTypeScriptApache-2.0

At a glance

What is it?
tslint-react is a package of React and JSX rules for TSLint, covering alignment, keys, self-closing elements, banned props and elements, boolean values, and translation functions. It is still receiving commits, but its newest published release dates from 2020, and the preset is versioned so that a minor bump can turn on stricter checks.
Who is it for?
Adopt tslint-react if your codebase is still on TSLint and you want JSX rules with automatic fixes for spacing and self-closing style, since the rules are the mature part of a deprecated linting stack. Do not adopt it for a new project, because the package depends on TSLint as a peer dependency and pins TypeScript versions from 2019 in its own development setup.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 11 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A rule set for TSLint, not a linter of its own

tslint-react is a package of lint rules about React and JSX, built to run inside TSLint. It has peer dependencies on TSLint and TypeScript, and the runtime dependency list is a single entry, tsutils, which is the shared utility library TSLint itself uses. That shape tells you most of what you need to know: this is a plugin for a linter that already exists in your project, not a replacement for it.

The package entry point is tslint-react.json, a preset configuration file rather than a module of runtime code, and the same file is copied into the build directory alongside package.json, README.md and LICENSE. The main entry being a JSON preset is unusual and useful, because it means the rules are enabled by configuration inheritance rather than by import.

The licence is Apache-2.0 and the repository is under the palantir organisation, which is also the organisation that maintains TSLint itself, so the rule conventions here are meant to match the core project's style. The topics on the repository include linting-rules, react, jsx, typescript and tslint, plus an octo-correct-managed label, which points to a project that is kept alive by automated dependency maintenance rather than by hand.

Wiring it up: extend the preset, then lint ts and tsx together

Usage is a configuration inheritance and one command. The sample configuration in the documentation shows a tslint.json living next to the node_modules folder, extending the standard TSLint preset and tslint-react, with a rules block where individual rules can be turned off.

js
{
  "extends": ["tslint:latest", "tslint-react"],
  "rules": {
    // override tslint-react rules here
    "jsx-wrap-multiline": false
  }
}

The order matters in practice, since the later entry wins for the rules both define, and the override block is how you deal with a rule whose opinion differs from your team's.

To lint both TypeScript and TSX files you run tslint with a glob covering both extensions.

That glob is the practical detail people miss, because a pattern that covers only .ts files silently skips every component file, and the JSX rules then appear to do nothing. Note also that the rules reach into .tsx files that are not valid TypeScript in the strict sense, so the linter invocation has to cover both extensions for the package to be useful at all.

The preset is semantically versioned, which is a trap for automated upgrades

The most important paragraph in the documentation is the one about semantic versioning, and it is unusual enough to quote the reasoning. The built-in configuration preset you get with extends tslint-react is versioned in a manner similar to TSLint's own presets and the TypeScript language itself. As new rules are added across minor versions, stricter checks may be enabled, and your code is not guaranteed to keep passing across those bumps.

The documented workaround is to declare a tilde dependency, for example ~1.0.0, so that npm upgrade or yarn upgrade never breaks the build.

This is a deliberate design choice rather than an accident, and there is a logic to it. A rules package that only ever adds checks would have to release new major versions for every rule, and major versions in a lint plugin are close to unheard of. Making the preset itself semantically versioned lets a minor release tighten behaviour in the way a new compiler version can tighten behaviour, which is defensible, but it means a caret dependency turns your lint config into a moving target. If your build runs lint as a gate, that is a build that can break on a dependency bump with no code change of yours.

The formatting rules are the fixable ones, and they are the most useful

The rule list divides fairly cleanly into two groups. The first group is mechanical style, and most of these carry an automatic code fix.

jsx-curly-spacing requires or bans spaces between curly brace characters in JSX, and jsx-equals-spacing does the same for the equals token in element attributes. Both take always or never as options. jsx-self-close enforces that elements with no children are written as self-closing, so a div with a class name and no children cannot be left as an open and close pair.

ts
  // bad
  <div className="foo"></div>
  // good
  <div className="foo" />

jsx-space-before-trailing-slash checks that self-closing elements have a space before the closing marker, and jsx-wrap-multiline enforces that multiline JSX expressions are wrapped in parentheses, with the opening parenthesis followed by a newline and the closing one preceded by a newline.

ts
  // bad
  const button = <button type="submit">
      Submit
  </button>;
  // good
  const button = (
      <button type="submit">
          Submit
      </button>
  );

That last rule is the one teams argue about most, and the sample configuration in the documentation turns it off, which is a good hint about how often it draws disagreement. jsx-alignment is in the same family, enforcing a consistent style for multiline JSX elements, which the documentation frames as promoting ease of editing through line-wise manipulations and small diffs.

The correctness rules are syntactic, and the documentation admits where they break

The second group is about React behaviour rather than formatting, and it is here that the caveats live.

jsx-key warns about missing key props in JSX element array literals and inside return statements of Array.prototype.map callbacks. The note attached to it is that the rule only does a simple check for .map syntax and does not inspect computed types of expressions, so it may produce false positives if you use an API that looks similar to .map. There is no semantic version of this rule, so a key produced by a helper function will not be seen.

jsx-no-bind forbids function binding in JSX attributes, with the same intent as jsx-no-lambda in avoiding excessive re-renders. The note says it currently only does a simple syntactic check, not a semantic one, because it does not use the type checker, so it may have rare false positives if you define your own .bind function and supply this as a parameter. jsx-no-lambda is the rule that explains the reasoning: creating new anonymous functions inside the render call stack works against pure component rendering, since an equality check between two lambdas always fails and forces the component to re-render more often than necessary.

The other rules are policy. jsx-ban-elements blacklists JSX elements with an optional explanatory message, jsx-ban-props does the same for props, jsx-boolean-value forces boolean attributes to be written consistently, jsx-no-string-ref flags the legacy string ref in favour of a callback, and jsx-use-translation-function enforces that plain string literals are disallowed in JSX when enabled, with options for allowing punctuation and HTML entities.

The version numbers and the commit history point in different directions

The release history is old and the commit history is not, and both facts matter.

The listed releases are 5.0.0 from 2020-04-21, 4.2.0 from 2020-01-21 and 4.1.0 from 2019-09-17. The default branch is master, the last push was on 2026-10-14, and the repository is not archived. So the code is still being touched while the published version has not moved since 2020, which is a common pattern for a package whose upstream tool has been superseded and whose repository is kept alive by maintenance automation rather than by feature work.

The manifest explains the vintage. The peer dependencies ask for tslint ^6.0.0 and typescript >=3.4.1, the development setup pins typescript to ~3.8.3, and the dev dependencies include tslint ^6.1.1 and typescript-tslint-plugin ^0.5.5. The package does not depend on ESLint at all, and there is no mention of a flat config or a new plugin system, which is the clearest signal in the file that this belongs to the TSLint era.

The build and test story is small and self-contained. The scripts are build with tsc, copy into the build directory, clean, lint with tslint against the project, a test script that runs a shell script from the scripts directory, and verify which chains build, lint and test together. The quick start in the documentation asks for Node v6 or later and yarn v0.22 or later, then yarn, yarn verify and yarn lint. The presence of a .vscode directory and a Circle CI configuration in the tree rounds out a project of its era.

Where tslint-react is the wrong tool

The first wrong-tool case is a new project. The rules are only consumable by TSLint, TSLint's own development has wound down, and this package's manifest is pinned to a TypeScript from 2019 in its own toolchain. A team starting fresh is better served by a linter whose ecosystem is still moving, and the JSX and React rules you actually wanted are available there in a maintained form.

The second case is a codebase that has already migrated away from TSLint. If your linting runs through ESLint, this package contributes nothing, and the migration cost is not the rules but the config, the fixer behaviour and the fact that some of these checks need type information, which a different rule engine has to provide differently.

The third case is teams that expect type-aware checks. Several rules here are explicitly syntactic, and the documentation is candid that jsx-key and jsx-no-bind can report false positives for code that is correct. If your React correctness policy depends on real type analysis, the value of these rules drops, and you are left with a formatting layer that is largely duplicated elsewhere.

The project itself is open about how it wants to grow. Rule suggestions are tracked as GitHub issues with a Type: Rule Suggestion label, tickets are roughly triaged by priority as P1, P2 and P3, and pull requests are welcome for new rules, especially those marked Status: Accepting PRs, with the guidance to follow the style conventions of the core TSLint project.

Editorial conclusion

Adopt tslint-react if your codebase is still on TSLint and you want JSX rules with automatic fixes for spacing and self-closing style, since the rules are the mature part of a deprecated linting stack. Do not adopt it for a new project, because the package depends on TSLint as a peer dependency and pins TypeScript versions from 2019 in its own development setup. Before you enable it, pin the dependency with a tilde, as the documentation instructs, because the built-in preset is semantically versioned in a way that can enable stricter checks on a minor upgrade, and decide rule by rule whether jsx-key and jsx-no-bind are worth their documented false positives.

Frequently asked questions

How do I add tslint-react rules to my TSLint configuration?

Add it to the extends array in your tslint.json, for example "extends": ["tslint:latest", "tslint-react"], and override individual rules in the rules block if you disagree with them. Then lint both file types with a glob covering the .ts and .tsx extensions so the JSX rules actually see your components.

Why did upgrading tslint-react start failing my lint build?

The built-in preset is semantically versioned so that new rules can enable stricter checks in minor releases, and your code is not guaranteed to keep passing across those bumps. The documentation advises declaring a tilde dependency such as ~1.0.0 so that npm upgrade or yarn upgrade never breaks the build.

Which tslint-react rules support an automatic fix?

The documentation marks jsx-curly-spacing, jsx-equals-spacing, jsx-self-close and jsx-space-before-trailing-slash as including an automatic code fix. The remaining rules, such as jsx-key, jsx-no-bind, jsx-no-lambda and jsx-ban-props, report failures without one.

Are the jsx-key and jsx-no-bind rules type aware?

No. jsx-key only does a simple check for .map syntax and does not inspect computed types of expressions, so it may report false positives for similar looking APIs. jsx-no-bind is a syntactic check that does not use the type checker, so a custom .bind function supplying this can trigger a rare false positive.

Is tslint-react still being maintained?

The repository is not archived and the last push was on 2026-10-14, but the newest listed release is 5.0.0 from 2020-04-21, and the manifest still declares peer dependencies on tslint ^6.0.0 and typescript >=3.4.1. Rule suggestions are tracked as GitHub issues and pull requests for new rules are welcome.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. palantir/tslint-react on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/palantir-tslint-react.svg)](https://hysenlabs.com/projects/palantir-tslint-react)

Was this useful?