Experimenting with Babel 7 + TypeScript + ESLint
The story of a (semi successful) attempt to get Babel 7 with TypeScript and ESLint with babel-eslint
to work nicely together.
A little bit of background info: I like to be cutting edge and that's why I like Babel a lot. It let's me use future JavaScript today. If there's a proposal for it, there's almost certainly a Babel plugin for it as well. What I also like is typed JavaScript. I used Flow a lot in the past but Flow rhymes with slow, and that's what it is: a memory eating, slow, unreliable monster.
I prefered Flow over TypeScript because I only wanted the type checking without going all-in on the whole TS ecosystem which always felt quite odd to me. I wanted to continue using all the tools I used over all the years. I wanted Babel, not tsc, I wanted ESLint not TSLint and I didn't want to use all the blah-blah-typescript-rewired-awesome-loader-yadayada hacks and workarounds either. In Flow it was as easy as yarn add @babel/preset-flow
and that was basically it.
So I was thrilled when I first heard about the possibility to use TypeScript with Babel 7 by installing @babel/preset-typescript
- in the same way I was able to use Flow just by installing @babel/preset-flow
. I was even more thrilled when I read about the plans of the TypeScript team on dropping TSLint in favor of ESLint.
Until recently I used pluggable-babel-eslint
together with eslint-plugin-typescript
and "everything" worked in a way I liked but both are deprecated now and will no longer be maintained. The repos say Babel-eslint supports TypeScript now (pluggable-babel-eslint
) and Use @typescript-eslint/eslint-plugin instead (eslint-plugin-typescript
) which is only half the truth. The whole Babel+TypeScript+ESLint thing looks like a total mess to me at the moment.
My goals with this experiment were to:
- use Babel 7 for transpilation of JSX and TypeScript by using
@babel/preset-react
and@babel/preset-typescript
- use
babel-eslint
as ESLint parser so ESLint can understand Babel features like Optional Chaining which TypeScript does not understand - use type definitions as replacement for PropTypes in React components
- use TypeScript for live type checking in VSCode and/or Atom, but only for things TypeScript does understand. Syntax that is later transpiled via Babel (like Optional Chaining) should ideally just be "ignored" without breaking the linting
- have all of this working with live linting in VSCode and Atom using ESLint.
- Put in another words: I (more or less) want to use TypeScript as a more widely adopted, more performant drop-in replacement for Flow.
Things that are working:
settings.json
:
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"]
[email protected]
I get no-undef
errors for every type and interface I define
tsc
which fails entirely on invalid syntax (e.g. when using syntax that's later transpiled via Babel).
Things that are not working:
@typescript-eslint/parser
does not work in files with syntax unknown to TypeScript. Sure, neither TypeScript nor @typescript-eslint/parser
care about the Babel config, but not only does it "not work", it breaks completely due to a parsing error (which is somehow logical …) so that all other ESLint errors are not shown in VSCode once a file contains non-TypeScript syntax. So using @typescript-eslint/parser
is not an option as I want to continue non-TypeScript compatible Babel features without breaking the linter completely.
tsc
for type checking. Not by using @ts-ignore
not by using @ts-nocheck
. Once you use non-standard syntax in .ts/.tsx files, you can't type check them on the CLI via tsc
anymore. For some reason it still works fine in VSCode.
Pick<Type, 'a' | 'b'>
results in an error [no-undef] 'Pick' is not defined
. That's kind of annoying and I found no other workaround than adding things like Pick
or ReturnType
to the globals
object of the ESLint config. I have no idea how viable this is in larger projects. It worked fine in one of my previous projects with pluggable-babel-eslint
so I guess it should not be that hard to get it working again.
Sure you could disable no-undef
in ESLint since TypeScript also takes care of that. Unless you're using "unparseable" non-TypeScript syntax like, you know, Optional Chaining
I don't know why, it worked already but it seems like I changed something in the eslintrc (or wherever) so that I now get Ok, got it. Seems like XYZ is not defined
when I use a type XYZ
[email protected]
does not understand TypeScript keywords like type
or interface
anymore, not even with @babel/preset-typescript
in the .babelrc
.
Summary
Issue | @typescript-eslint/parser | [email protected] | [email protected] |
---|---|---|---|
ESLint results with non-standard (Babel) syntax | |||
TypeScript errors shown in VS Code | |||
TypeScript keywords like Pick or ReturnType correctly not marked as no-undef error |
|||
Types and Interfaces not falsely marked as no-undef |
I'd love to see a fully green babel-eslint@11
column. Not sure if these 'Foo' is not defined
errors in babel-eslint@11
is regression or if I'm just configuring anything wrong.