TSX
This page curates a list of example ast-grep rules to check and to rewrite TypeScript with JSX syntax.
TypeScript and TSX are different.
TypeScript is a typed JavaScript extension and TSX is a further extension that allows JSX elements. They need different parsers because of conflicting syntax.
TS allows both the as
operator and angle brackets (<>
) for type assertions. While TSX only allows the as
operator because it interprets angle brackets as JSX elements.
Avoid &&
short circuit in JSX Has Fix
Description
In React, you can conditionally render JSX using JavaScript syntax like if
statements, &&
, and ? :
operators. However, you should almost never put numbers on the left side of &&
. This is because React will render the number 0
, instead of the JSX element on the right side. A concrete example will be conditionally rendering a list when the list is not empty.
This rule will find and fix any short-circuit rendering in JSX and rewrite it to a ternary operator.
YAML
id: do-what-brooooooklyn-said
language: Tsx
rule:
kind: jsx_expression
has:
pattern: $A && $B
not:
inside:
kind: jsx_attribute
fix: "{$A ? $B : null}"
Example
<div>{ list.length && list.map(i => <p/>) }</div>
Diff
<div>{ list.length && list.map(i => <p/>) }</div>
<div>{ list.length ? list.map(i => <p/>) : null }</div>
Contributed by
Herrington Darkholme, inspired by @Brooooook_lyn
Rewrite MobX Component Style Has Fix
Description
React and MobX are libraries that help us build user interfaces with JavaScript.
React hooks allow us to use state and lifecycle methods in functional components. But we need follow some hook rules, or React may break. MobX has an observer
function that makes a component update when data changes.
When we use the observer
function like this:
export const Example = observer(() => {…})
ESLint, the tool that checks hooks, thinks that Example
is not a React component, but just a regular function. So it does not check the hooks inside it, and we may miss some wrong usages.
To fix this, we need to change our component style to this:
const BaseExample = () => {…}
const Example = observer(BaseExample)
Now ESLint can see that BaseExample
is a React component, and it can check the hooks inside it.
YAML
id: rewrite-mobx-component
language: typescript
rule:
pattern: export const $COMP = observer($FUNC)
fix: |-
const Base$COMP = $FUNC
export const $COMP = observer(Base$COMP)
Example
export const Example = observer(() => {
return <div>Hello World</div>
})
Diff
export const Example = observer(() => {
return <div>Hello World</div>
})
const BaseExample = () => {
return <div>Hello World</div>
}
export const Example = observer(BaseExample)
Contributed by
Avoid Unnecessary React Hook
Description
React hook is a powerful feature in React that allows you to use state and other React features in a functional component.
However, you should avoid using hooks when you don't need them. If the code does not contain using any other React hooks, it can be rewritten to a plain function. This can help to separate your application logic from the React-specific UI logic.
YAML
id: unnecessary-react-hook
language: Tsx
utils:
hook_call:
has:
kind: call_expression
regex: ^use
stopBy: end
rule:
any:
- pattern: function $FUNC($$$) { $$$ }
- pattern: let $FUNC = ($$$) => $$$
- pattern: const $FUNC = ($$$) => $$$
has:
pattern: $BODY
kind: statement_block
stopBy: end
constraints:
FUNC: {regex: ^use }
BODY: { not: { matches: hook_call } }
Example
function useIAmNotHookActually(args) {
console.log('Called in React but I dont need to be a hook')
return args.length
}
const useIAmNotHookToo = (...args) => {
console.log('Called in React but I dont need to be a hook')
return args.length
}
function useTrueHook() {
useEffect(() => {
console.log('Real hook')
})
}