Custom rules are written by defining a visitor object within the rules array of defineConfig. Rules run on the TypeScript AST.
Key capabilities:
- Type Information: Access the type checker via
context.checker.getTypeAtLocation(node). - AST Utilities:
context.utils provides helpers like typeOrUnionHasFlag. - Improved Types:
tsl provides rewritten AST types for better type narrowing and exhaustive switches.
Use ast-explorer.dev to explore the AST and ts-ast-viewer to explore type information.
import { type AST, core, defineConfig } from "tsl";
import { SyntaxKind, TypeFlags } from "typescript";
export default defineConfig({
rules: [
...core.all(),
{
name: "org/useLogger",
visitor: {
CallExpression(context, node) {
if (
node.expression.kind === SyntaxKind.PropertyAccessExpression
&& node.expression.expression.kind === SyntaxKind.Identifier
&& node.expression.expression.text === "console"
) {
node.expression.expression satisfies AST.Identifier;
context.report({ node, message: "Use logger instead" });
}
},
},
},
{
name: "org/jsxNoNumberTruthiness",
visitor: {
BinaryExpression(context, node) {
if (
node.parent.kind === SyntaxKind.JsxExpression
&& node.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken
) {
const type = context.checker.getTypeAtLocation(node.left);
if (context.utils.typeOrUnionHasFlag(type, TypeFlags.NumberLike)) {
context.report({
node,
message: "Don't use logical expression on a number inside JSX...",
});
}
}
},
},
},
],
});