ota-meshi/eslint-plugin-astro

JSX return type and @typescript-eslint/no-unsafe-return

david-abell opened this issue · 5 comments

Before You File a Bug Report Please Confirm You Have Done The Following...

  • I have tried restarting my IDE and the issue persists.
  • I have updated to the latest version of the packages.

What version of ESLint are you using?

8.33.0

What version of eslint-plugin-astro are you using?

0.23.0

What did you do?

Configuration .eslintrc.json
{
  "env": {
    "browser": true,
    "node": true
  },
  "extends": [
    // ...
    "plugin:astro/recommended",
    "eslint:recommended",
    "plugin:jsx-a11y/recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/recommended-requiring-type-checking",
    "prettier"
  ],
  // ...
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "project": "./tsconfig.eslint.json"
  },
  "overrides": [
    {
      "files": ["*.astro"],
      "parser": "astro-eslint-parser",
      "parserOptions": {
        "parser": "@typescript-eslint/parser",
        "extraFileExtensions": [".astro"],
        "project": "./tsconfig.eslint.json"
      },
      "rules": {
        // override/add rules settings here, such as:
        // "astro/no-set-html-directive": "error"
        // "no-plusplus": "off",
        "no-restricted-syntax": [
          "error",
          "ForInStatement",
          "LabeledStatement",
          "WithStatement"
        ]
      }
    }
    // ...
  ]
}
Configuration tsconfig.eslint.json
{
  "extends": "./tsconfig.json",
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.js",
    "src/**/*.jsx",
    "src/**/*.astro",
    "test/**/*.ts",
    "globals.d.ts",
    "astro.config.mjs"
  ]
}

Example .astro file

---
	let cards = [
  {
    href: "https://docs.astro.build/",
    title: "Documentation",
    body: "Learn how Astro works and explore the official API docs.",
  },
  {
    href: "https://astro.build/integrations/",
    title: "Integrations",
    body: "Supercharge your project with new frameworks and libraries.",
  },
  {
    href: "https://astro.build/themes/",
    title: "Themes",
    body: "Explore a galaxy of community-built starter themes.",
  },
];
---

<html lang="en">
	<head>
		<meta charset="utf-8" />
		<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
		<meta name="viewport" content="width=device-width" />
		<meta name="generator" content={Astro.generator} />
		<title>Astro</title>
	</head>
	<body>
	<li>
  {
    cards.map((card) => (
      // next line has following error: Unsafe return of an `any` typed value. eslint(@typescript-eslint/no-unsafe-return)
      <div>{card.href}</div>
    ))
  }
</li>
    <div class="tags">
    {
      ["a", "b", "c"].map((tag) => (
        <p class={tag}>Tag:{tag} This p tag triggers unsafe return of an `any` typed value.</p>
      ))
    }
  </div>
	</body>
</html>

What did you expect to happen?

no error

What actually happened?

Unsafe return of an any typed value.eslint@typescript-eslint/no-unsafe-return

Link to Minimal Reproducible Example

https://stackblitz.com/edit/github-tekdct?file=src/pages/index.astro

Additional comments

run npx eslint src/pages/index.astro on linked stackblitz example for error in action.

Referred to file issue here from Astro withastro/astro#6280 (comment)

stackblitz is not suitable for reproduction. I can't debug Node.js.
Could you provide it on GitHubRepo? Also include the lint command in your package.json.
I can debug Node.js using Codespaces.

Repo is https://github.com/david-abell/astro-jsx-no-unsafe

Script is lint in package.json

Let me know if there is anything else I can help with

I think it can be solved by adding a d.ts file like the following and including the d.ts file in tsconfig.eslint.json.

import 'astro/astro-jsx'

declare global {
    namespace JSX {
        type Element = HTMLElement
        // type Element = astroHTML.JSX.Element // We want to use this, but it is defined as any.
        type IntrinsicElements = astroHTML.JSX.IntrinsicElements
    }
}

This seems to be the solution.

JSX types appear to not be imported if no JSX framework is included in the project.

I tested out The official minimal React template and it does not require importing and declaring the JSX namespace like this to work properly with eslint-plugin-astro

If others encounter this, the specific minimal setup that worked for me was the above recommended d.ts namespace declaration and the below configurations:

eslintrc.cjs

module.exports = {
  // The plugins and shared settings I was testing
  plugins: ["jsx-a11y", "@typescript-eslint"],
  extends: [
    // ...
    "eslint:recommended",
    "plugin:astro/recommended",
    "plugin:jsx-a11y/recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/recommended-requiring-type-checking",
    "prettier",
  ],
 // This was needed because parser and parser options can get overridden by shareable configurations 
  parser: "@typescript-eslint/parser",
  parserOptions: {
    project: "./tsconfig.eslint.json",
    extraFileExtensions: [".astro"],
  },
  //  This is needed for a cjs configuration file since the project type in package.json is set as "module"
  env: {
    node: true,
  },
  // This is the default recommended overrides for eslint-plugin-astro
  overrides: [
    {
      // Define the configuration for `.astro` file.
      files: ["*.astro"],
      // Allows Astro components to be parsed.
      parser: "astro-eslint-parser",
      // Parse the script in `.astro` as TypeScript by adding the following configuration.
      // It's the setting you need when using TypeScript.
      parserOptions: {
        parser: "@typescript-eslint/parser",
        extraFileExtensions: [".astro"],
      },
      rules: {
        // override/add rules settings here, such as:
        // "astro/no-set-html-directive": "error"
      },
    },
    // ...
  ],
};

tsconfig.eslint.json

{
  "extends": "./tsconfig.json",
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.js",
    "src/**/*.jsx",
    "src/**/*.astro",
    "astro.config.mjs",
    ".eslintrc.cjs",
    "d.ts"
  ]
}