Skip to content

Commit 679145c

Browse files
update
1 parent 833e61e commit 679145c

File tree

1 file changed

+61
-23
lines changed

1 file changed

+61
-23
lines changed

website/blog/typed-napi.md

Lines changed: 61 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,93 @@
1-
Improve Napi Typing
1+
# Improve Napi Typing
22

33
What's type safety? Why?
44

55
https://github.com/ast-grep/ast-grep/issues/1669
66
https://github.com/ast-grep/ast-grep/issues/48
77

8-
It guides one to write comprehensive AST code (in case people forget to handle some cases)
8+
Writing AST manipulation code is hard. Even if we have a lot of helpful interactive tool, it's still hard to handle all edge cases.
99

10-
# What are good TypeScript types?
10+
AST types are good guiderail to write comprehensive AST manipulation code. It guides one to write comprehensive AST manipulation code (in case people forget to handle some cases). Using exhaustive checking, one can ensure that all cases are handled.
11+
12+
While ast-grep napi is a convenient tool to programmatically process AST , but it lacks the type information to guide user to write robust logic to handle all potential code. Thank to Mohebifar from codemod, ast-grep napi now can provide type information via nodejs API.
13+
14+
The solution to solve the problem is generating types from the static information provided by AST parser library, and using several TypeScript tricks to provide a good typing API.
15+
16+
## What are good TypeScript types?
17+
18+
before we talk about how we achieve the goal, let's talk about what are good TypeScript types.
19+
20+
Designing a good library in the modern JavaScript world is not only about providing good API naming, documentation and examples, but also about providing good TypeScript types. A good API type should be:
1121

1222
* Correct: reject invalid code and accept valid code
1323
* Concise: easy to read, especially in hover and completion
14-
* Robust: easy to refactor
15-
* Performant: fast to compile
24+
* Robust: easy to spot the compile error when you make a mistake. it should not report a huge error that doesn't fit a screen
25+
* Performant: fast to compile. complex types can slow down the compiler
26+
27+
28+
It is really hard to provide a type system that is both Sound and Complete. This is similar to provide a good typing API.
29+
30+
https://logan.tw/posts/2014/11/12/soundness-and-completeness-of-the-type-system/#:~:text=A%20type%2Dsystem%20is%20sound,any%20false%20positive%20%5B2%5D.
31+
32+
TS libs nowaday probably pay too much attention to correctness IMHO.
33+
Having a type to check your path parameter in your routing is cool, but what's the cost?
34+
35+
Designing a good TypeScript type is essentially a trade-off of these four aspects.
1636

1737
# TreeSitter's types
1838

19-
Tree-Sitter's official API is untyped. However it provides static node types in json
39+
Let's come back to ast-grep's problem. ast-grep is based on Tree-Sitter.
2040

21-
1. json hosted by parser library repo
22-
needs type generation(layman's type provider)
23-
2. contains a lot unnamed kinds
41+
Tree-Sitter's official API is untyped. It provies a uniform API to access the syntax tree across different languages. A node in Tree-Sitter has several methods like `kind`, `field`, `parent`, `children`, `range`, `text`, etc.
42+
43+
However, a specific language's syntax tree has a specific structure. For example, a function declaration in JavaScript has a `function` keyword, a name, a list of parameters, and a body. Other AST parser libraries encode this structure in their AST object types. For example, a `function_declaration` has fields like `parameters` and `body`.
44+
45+
Fortunately tree-sitter provides static node types in json.
46+
There are several challenges to generate TypeScript types from tree-sitter's static node types.
47+
48+
1. json is hosted by parser library repo
49+
We needs type generation (it is like layman's type provider)
50+
2. json contains a lot unnamed kinds
2451
You are writing a compiler plugin, not elementary school math homework
25-
3. has alias type
52+
3. json has alias type
2653

2754

28-
# Big Idea
55+
## Design Type
2956

3057
1. lenient type check if no information
3158
2. more strict checking if refined
3259

3360

34-
# APIs
61+
## Define Type
3562

36-
## Prune unnamed kinds
63+
### Prune unnamed kinds
3764
For example `+`/`-`/`*`/`/` is too noisy for a general AST library
3865

39-
## `ResolveType<M, T>`
66+
### `ResolveType<M, T>`
4067

4168
Use type script to resolve type alias
4269

43-
## `Kinds<M>`
70+
### `Kinds<M>`
4471

4572
1. string literal completion with `LowPriorityString`
4673
2. lenient
4774

48-
Problem?
75+
Problem? open-ended union is not well supported in TypeScript
4976

5077
https://github.com/microsoft/TypeScript/issues/33471
5178
https://github.com/microsoft/TypeScript/issues/26277
5279

53-
## Distinguish general `string`ly kinds and specific kinds
80+
81+
### Distinguish general `string`ly kinds and specific kinds
5482

5583
Note `SgNode<'expression' | 'type'>` is different from `SgNode<'expression'> | SgNode<'type'>`
5684

5785
ast-grep uses a trick via the type `RefineNode<>` to let you switch between the two
5886

5987

60-
## Refine Node, Manually
88+
## Refine Type
89+
90+
### Refine Node, Manually
6191

6292
1.via `sgNode.find<"KIND">`
6393
2.via `sgNode.is<"KIND">`, One time type narrowing
@@ -71,12 +101,12 @@ interface NodeMethod<K> {
71101
}
72102
```
73103

74-
## Refine Node, Automatically
104+
### Refine Node, Automatically
75105

76106
`sgNode.field("kind")` will
77107

78108

79-
## Exhaustive Checking via `sgNode.kindToRefine`
109+
### Exhaustive Checking via `sgNode.kindToRefine`
80110

81111
Only available for node with specific kinds
82112

@@ -95,7 +125,9 @@ switch (func.kindToRefine) {
95125
}
96126
```
97127

98-
## Typed Rule!
128+
## Confine Types
129+
130+
### Typed Rule!
99131

100132
```typescript
101133
sgNode.find({
@@ -106,9 +138,15 @@ sgNode.find({
106138
})
107139
```
108140

109-
## Opt-in refinement for better compile time performance
110141

111-
# Ending
142+
### Opt-in refinement for better compile time performance
143+
144+
## Ending
145+
146+
I'm very thrilled to see the future of AST manipulation in TypeScript.
147+
This feature enables users to switch freely between untyped AST and typed AST.
148+
149+
it is like biome / rowan
112150

113151
https://x.com/hd_nvim/status/1868453729940500924
114152
There are very few devs that understands Rust deeply enough and compiler deeply enough that also care about TypeScript in web dev enough to build something for web devs in Rust

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy