|
| 1 | +--- |
| 2 | +authors: |
| 3 | + - image_url: https://www.joshuakgoldberg.com/img/josh.jpg |
| 4 | + name: Josh Goldberg |
| 5 | + title: TypeScript ESLint Maintainer |
| 6 | + url: https://github.com/JoshuaKGoldberg |
| 7 | +description: Describing what an AST (Abstract Syntax Tree) is and why it's useful for ESLint and TypeScript tooling. |
| 8 | +slug: asts-and-typescript-eslint |
| 9 | +tags: [ast, abstract syntax tree, parser, parsing, prettier] |
| 10 | +title: ASTs and TypeScript-ESLint |
| 11 | +--- |
| 12 | + |
| 13 | +Programmers who work with tools like [ESLint](https://eslint.org) and [Prettier](https://prettier.io) often refer to ASTs. |
| 14 | +But what is an AST, why is it useful for these kinds of tools, and how does that interact with ESLint and TypeScript tooling? |
| 15 | +Let's dig in! |
| 16 | + |
| 17 | +## What's an AST? |
| 18 | + |
| 19 | +_Static analysis_ tools are those that look at code without running it. |
| 20 | +They typically _parse_ code, or transform it from a string into a standard format they can reason about known as an **Abstract Syntax Tree** (AST). |
| 21 | +ASTs are called such because although they might contain information on the location of constructs within source code, they are an abstract representation that cares more about the semantic structure. |
| 22 | + |
| 23 | +> In other words, an AST is a description of your code's syntax. |
| 24 | +
|
| 25 | +### An Example AST |
| 26 | + |
| 27 | +Take this single line of code: |
| 28 | + |
| 29 | +```js |
| 30 | +1 + 2; |
| 31 | +``` |
| 32 | + |
| 33 | +ESLint's AST format, **[ESTree]**, would describe that line of code as an object like: |
| 34 | + |
| 35 | +```json |
| 36 | +{ |
| 37 | + "type": "ExpressionStatement", |
| 38 | + "expression": { |
| 39 | + "type": "BinaryExpression", |
| 40 | + "left": { |
| 41 | + "type": "Literal", |
| 42 | + "value": 1, |
| 43 | + "raw": "1" |
| 44 | + }, |
| 45 | + "operator": "+", |
| 46 | + "right": { |
| 47 | + "type": "Literal", |
| 48 | + "value": 2, |
| 49 | + "raw": "2" |
| 50 | + } |
| 51 | + } |
| 52 | +} |
| 53 | +``` |
| 54 | + |
| 55 | +Each piece of code described within an AST description is referred to as a **node**, or AST node. |
| 56 | +Each node is given a **node type** indicating the type of code syntax it represents |
| 57 | +That code snippet includes four nodes of the following types: |
| 58 | + |
| 59 | +- _ExpressionStatement_: `1 + 2;` |
| 60 | +- _BinaryExpression_: `1 + 2` |
| 61 | +- _Literal_: `1` |
| 62 | +- _Literal_: `2` |
| 63 | + |
| 64 | +That ESTree object representation of the code is what static analysis tools such as [ESLint](https://eslint.org) and [Prettier](https://prettier.io) work with. |
| 65 | + |
| 66 | +## AST Formats |
| 67 | + |
| 68 | +ESTree is more broadly used than just for ESLint -- it is a popular community standard. |
| 69 | +ESLint's built-in parser that outputs an ESTree-shaped AST is also a separate package, called **[Espree]**. |
| 70 | + |
| 71 | +TypeScript has its own separate AST format, often referred to as the TypeScript AST. |
| 72 | +Because TypeScript is developed separately and with different goals from ESLint, ESTree, and Espree, its AST also represents nodes differently in many cases. |
| 73 | + |
| 74 | +- TS's AST is optimized for its use case of parsing incomplete code and typechecking. |
| 75 | +- ESTree is unoptimized and intended for "general purpose" use-cases of traversing the AST. |
| 76 | + |
| 77 | +ESLint rules are by default only given nodes in the ESTree AST format - which has no knowledge of TypeScript-specific syntax such as interfaces. |
| 78 | +On the other hand, TypeScript's type checking APIs require nodes in the TypeScript AST format. |
| 79 | + |
| 80 | +### Enter TSESTree |
| 81 | + |
| 82 | +To resolve the incompatibilities between ESTrees and the TypeScript AST typescript-eslint provides its own [`@typescript-eslint/parser` package](https://typescript-eslint.io/architecture/Parser.mdx) which: |
| 83 | + |
| 84 | +1. First parses TypeScript syntax into a TypeScript AST |
| 85 | +1. Creates an ESTree AST based on that TypeScript AST |
| 86 | +1. Keeps track of equivalent nodes across each AST |
| 87 | + |
| 88 | +By creating both an ESTree AST and a TypeScript AST, the typescript-eslint parser allows ESLint rules to work with TypeScript code. |
| 89 | +That's why the [Getting Started guide](https://typescript-eslint.io/getting-started) for typescript-eslint has you specify `parser: '@typescript-eslint/parser'` in your ESLint config! |
| 90 | + |
| 91 | +We commonly refer to the ESTree format that also includes TypeScript-specific syntax as **TSESTree**. |
| 92 | + |
| 93 | +### AST Playground |
| 94 | + |
| 95 | +The [TypeScript ESLint playground](https://typescript-eslint.io/play#showAST=es) contains an AST explorer that generates an interactive AST for any code entered into the playground. |
| 96 | +You can activate it under _Options_ > _AST Explorer_ on its left sidebar by selecting the value of _AST Viewer_. |
| 97 | + |
| 98 | +## Further Resources |
| 99 | + |
| 100 | +You can play more with various other ASTs on [astexplorer.net], including those for other languages such as CSS and HTML. |
| 101 | + |
| 102 | +The [AST Wikipedia article](https://en.wikipedia.org/wiki/Abstract_syntax_tree) has a great deal more context and history on ASTs. |
| 103 | + |
| 104 | +### Glossary |
| 105 | + |
| 106 | +Putting together all the terms introduces in this article: |
| 107 | + |
| 108 | +- **AST (Abstract Syntax Tree)**: An object representation of your code's syntax. |
| 109 | +- **Espree**: ESLint's built-in parser that outputs an ESTree-shaped AST. |
| 110 | +- **ESTree**: The AST specification used by ESLint and other common JavaScript tools. |
| 111 | +- **Node Type**: What kind of code syntax an AST node refers to, such as _BinaryExpression_ or _Literal_. |
| 112 | +- **Node**: A single range of code syntax in an AST. |
| 113 | +- **Parser**: A tool that reads in a string and outputs an AST. |
| 114 | +- **TSESTree**: Our extension to the ESTree AST format that also includes TypeScript-specific syntax. |
| 115 | + |
| 116 | +### TypeScript Lint Rules and ASTs |
| 117 | + |
| 118 | +Interested in how these ASTs work with ESLint rules? |
| 119 | +We collaborated with our friends at Sourcegraph on a [Tour de Source on TypeScript ESLint](https://sourcegraph.com/notebooks/Tm90ZWJvb2s6MTA2OA==). |
| 120 | +Read on to learn how ESLint rules use ASTs to analyze code files and, thanks to `@typescript-eslint/parser`, call TypeScript's type checking APIs to analyze code. |
| 121 | + |
| 122 | +[astexplorer.net]: https://astexplorer.net |
| 123 | +[espree]: https://github.com/eslint/espree |
| 124 | +[estree]: https://github.com/ESTree/ESTree |
0 commit comments