1
votes

I have a React build configuration using Webpack, ESlint, Prettier and TypeScript.

When I run the build it looks like I'm getting TypeScript linting errors that should be nullified by the @typings/react or @typings/react-dom packages.

Looking at the documentation I shouldn't need to define accessibility modifiers or return types for React Components: https://www.typescriptlang.org/docs/handbook/jsx.html

This seems like the same issue as here: Missing return type on function - in react (typescript) code

but installing the typings packages hasn't resolved the issue for me. Please note, I have also tried removing the @typings/react package as the @typings/react-dom has this as a dependency and this doesn't resolve the issue.

Webpack config

const webpack = require('webpack');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const path = require('path');

const createWebpackConfig = () => {
  const isProd =
    process.env &&
    process.env.NODE_ENV &&
    process.env.NODE_ENV === 'production';

  return {
    entry: ['@babel/polyfill', './index.tsx'],
    mode: isProd ? 'production' : 'development',
    module: {
      rules: [
        {
          enforce: 'pre',
          test: /(\.jsx|\.js|\.ts|\.tsx)$/,
          exclude: /node_modules/,
          loader: 'eslint-loader'
        },
        {
          test: /(\.jsx|\.js)$/,
          exclude: /node_modules/,
          use: {
            loader: 'babel-loader',
            options: {
              presets: [
                '@babel/preset-react',
                [
                  '@babel/preset-env',
                  {
                    targets: 'cover 99.5% in GB'
                  }
                ]
              ],
              plugins: [
                '@babel/plugin-proposal-class-properties',
                '@babel/plugin-proposal-object-rest-spread'
              ],
              cacheDirectory: true
            }
          }
        },
        {
          test: /(\.tsx|\.ts)$/,
          exclude: /node_modules/,
          use: {
            loader: 'babel-loader',
            options: {
              presets: [
                '@babel/preset-typescript',
                '@babel/preset-react',
                [
                  '@babel/preset-env',
                  {
                    targets: 'cover 99.5% in GB'
                  }
                ]
              ],
              plugins: [
                '@babel/plugin-proposal-class-properties',
                '@babel/plugin-proposal-object-rest-spread'
              ],
              cacheDirectory: true
            }
          }
        }
      ]
    },
    resolve: {
      modules: [path.resolve(__dirname, '/'), 'node_modules'],
      extensions: ['.ts', '.tsx', '.js', '.jsx'],
      enforceExtension: false
    },
    target: 'web',
    optimization: {
      splitChunks: {
        chunks: 'all',
        maxInitialRequests: Infinity,
        minSize: 0,
        cacheGroups: {
          vendor: {
            test: /[\\/]node_modules[\\/]/,
            name: 'vendor'
          },
          main: {
            name: 'main'
          }
        }
      }
    },
    output: {
      path: path.join(__dirname, 'bundles'),
      filename: '[name].app.js',
      chunkFilename: '[name].bundle.js',
      pathinfo: true
    },
    plugins: [
      new CaseSensitivePathsPlugin(),
      new webpack.DefinePlugin({
        'process.env': {
          NODE_ENV: JSON.stringify(isProd ? 'production' : 'development')
        }
      })
    ]
  };
};

module.exports = createWebpackConfig;

ESLint config

{
  "parser": "@typescript-eslint/parser", // Specifies the ESLint parser
  "extends": [
    "plugin:react/recommended",
    "plugin:@typescript-eslint/recommended", // Uses the recommended rules from the @typescript-eslint/eslint-plugin
    "prettier/@typescript-eslint", // Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier
    "plugin:prettier/recommended" // Enables eslint-plugin-prettier and displays prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array.
  ],
  "parserOptions": {
    "ecmaVersion": 10, // Allows for the parsing of modern ECMAScript features
    "sourceType": "module", // Allows for the use of imports
    "jsx": true
  },
  "rules": {
    "prettier/prettier": [
      "error",
      {
        "singleQuote": true,
        "endOfLine": "auto"
      }
    ]
  }
}

tsconfig.json

{
  "compilerOptions": {
    "module": "esnext",
    "allowSyntheticDefaultImports": true,
    "allowJs": true,
    "jsx": "preserve"
  },
  "exclude": ["node_modules"]
}

package.json

{
  "name": "reacttypescripttest",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "cross-env NODE_ENV=development webpack --config ./webpack.config.js --progress --colors --watch --display-error-details"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@babel/core": "^7.5.5",
    "@babel/plugin-proposal-class-properties": "^7.5.5",
    "@babel/plugin-proposal-object-rest-spread": "^7.5.5",
    "@babel/polyfill": "^7.4.4",
    "@babel/preset-env": "^7.5.5",
    "@babel/preset-react": "^7.0.0",
    "@babel/preset-typescript": "^7.3.3",
    "@types/react": "^16.8.24",
    "@types/react-dom": "^16.8.5",
    "@typescript-eslint/eslint-plugin": "^1.13.0",
    "@typescript-eslint/parser": "^1.13.0",
    "babel-loader": "^8.0.6",
    "case-sensitive-paths-webpack-plugin": "^2.2.0",
    "cross-env": "^5.2.0",
    "eslint": "^6.1.0",
    "eslint-config-prettier": "^6.0.0",
    "eslint-loader": "^2.2.1",
    "eslint-plugin-prettier": "^3.1.0",
    "eslint-plugin-react": "^7.14.3",
    "mini-css-extract-plugin": "^0.8.0",
    "prettier": "^1.18.2",
    "prettier-eslint": "^9.0.0",
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "typescript": "^3.5.3",
    "webpack-cli": "^3.3.6"
  },
  "devDependencies": {
    "webpack": "^4.39.1"
  }
}

File causing error (index.tsx)

import React from 'react';
import ReactDOM from 'react-dom';

class App extends React.Component {
  render() {
    return <div>Running!</div>;
  }
}

ReactDOM.render(<App />, document.getElementById('app'));

Errors

  5:3  error    Missing accessibility modifier on method definition render  @typescript-eslint/explicit-member-accessibility
  5:9  warning  Missing return type on function                             @typescript-eslint/explicit-function-return-type
2

2 Answers

4
votes

The first error Missing accessibility modifier on method definition render is saying that you did not declare your render method as public or private or any other type (more reading on types. When working with Typescript all class methods need to have be declared accordingly, depending if you want to have them accessible outside your class instance or not. For render method it should be public. Code below should work nicely for you:

public render() {
   return <div>Running!</div>;
}

When it comes the 2nd error your're having, it means that your linter expects the render method to have declared what's the output of its' execution. The correct type for render method is React.ReactNode, so your final code should look like below (assuming you're not importing ReactNode in the import statement earlier)

public render(): React.ReactNode {
   return <div>Running!</div>;
}

Edit 1

Even if TS itself doesn't require all these annotations, the linter you're using does. See their default rules- as you can see, the rules you're having trouble with are not turned off. The solution there would be disabling them in your app eslint config, like below:

"rules": {
   "@typescript-eslint/explicit-function-return-type": "off",
   "@typescript-eslint/explicit-member-accessibility": "off"
}
0
votes

If anyone is running into this AND using a tsx file already. Makre sure that you've configured vscode to associate tsx files with TypescriptReact and not just Typescript. When the tsx file is open, bottom right click on Typescript and set association. vscode status bar