React Typescript: Prop type is not being checked

Viewed 602

I am in the process of migrating my React project to typescript. I've managed to convert a smaller component and it's working as expected.

One issue, however, is that one of my props does not throw an error if I pass in an unexpected data type.

Here is my component.

import React, { useEffect, useState, ReactElement } from "react";

interface Props {
  delay: number,
  children: ReactElement,
  reset(): void
}

const Expire = ({delay, children, reset}: Props) => {
  const [visible, setVisible] = useState<Boolean>(true);

  useEffect(() => {
    setTimeout(() => {
      setVisible(false);
      if (reset) {
          reset();
      }
    }, delay);
  }, [delay]);

  return visible ? <div>{children}</div> : <div/>;
};

export default Expire;

I call it like this.

<Expire delay="5000" reset={resetState}>
 <div className="alert alert-danger">
  <span>{message || "Oops! Something went wrong. Please try again."}</span>
 </div>
</Expire>

For the delay prop, if I pass something like "some-string" it compiles fine and doesn't throw an error.

Am I missing something? I thought the whole point of TS is that it should catch things like this.

.tsconfig.json

{
  "compilerOptions": {
    "target": "es2016",                                  /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
    "jsx": "react",                                      /* Specify what JSX code is generated. */
    /* Modules */
    "module": "es2020",                                /* Specify what module code is generated. */
    "moduleResolution": "node",                       /* Specify how TypeScript looks up a file from a given module specifier. */
    "baseUrl": "./",                                  /* Specify the base directory to resolve non-relative module names. */
    /* Interop Constraints */
    "allowSyntheticDefaultImports": true,             /* Allow 'import x from y' when a module doesn't have a default export. */
    "esModuleInterop": true,                             /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
    "forceConsistentCasingInFileNames": true,            /* Ensure that casing is correct in imports. */
    /* Type Checking */
    "strict": true,                                      /* Enable all strict type-checking options. */
    "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied `any` type.. */
    /* Completeness */
    "skipLibCheck": true                                 /* Skip type checking all .d.ts files. */
  },
  "include": ["resources/js/**/*"]  // Frontend paths pattern
}

package.json

{
    "private": true,
    "scripts": {
        "dev": "npm run development",
        "development": "mix",
        "watch": "mix watch",
        "watch-poll": "mix watch -- --watch-options-poll=1000",
        "hot": "mix watch --hot",
        "prod": "npm run production",
        "production": "mix --production",
        "test": "jest --env=jsdom"
    },
    "devDependencies": {
        "@babel/preset-react": "^7.13.13",
        "@tailwindcss/forms": "^0.2.1",
        "alpinejs": "^2.7.3",
        "autoprefixer": "^10.1.0",
        "axios": "^0.21",
        "bootstrap": "^4.6.0",
        "enzyme": "^3.11.0",
        "enzyme-adapter-react-16": "^1.15.6",
        "enzyme-to-json": "^3.6.2",
        "jest": "^27.0.4",
        "jquery": "^3.6",
        "laravel-mix": "^6.0.27",
        "lodash": "^4.17.19",
        "popper.js": "^1.16.1",
        "postcss": "^8.3.1",
        "postcss-import": "^12.0.1",
        "react": "^17.0.2",
        "react-dom": "^17.0.2",
        "react-test-renderer": "^17.0.2",
        "regenerator-runtime": "^0.13.7",
        "resolve-url-loader": "^3.1.2",
        "robust-point-in-polygon": "^1.0.3",
        "sass": "^1.32.11",
        "sass-loader": "^11.0.1",
        "tailwindcss": "^2.2.7",
        "ts-loader": "^9.2.6",
        "typescript": "^4.5.2",
        "webpack-cli": "^4.6.0"
    },
    "dependencies": {
        "@material-ui/core": "^4.11.4",
        "@material-ui/icons": "^4.11.2",
        "@material-ui/lab": "^4.0.0-alpha.58",
        "react-bootstrap": "^1.5.2"
    },
    "babel": {
        "presets": [
            "@babel/preset-env",
            "@babel/preset-react"
        ],
        "plugins": [
            "@babel/plugin-proposal-class-properties"
        ]
    },
    "jest": {
        "moduleNameMapper": {
            "\\.(scss|css)$": "<rootDir>/tests/js/__mocks__/styleMock.js"
        },
        "testRegex": "tests/js/.*.test.js$",
        "snapshotSerializers": [
            "enzyme-to-json/serializer"
        ],
        "setupFiles": [
            "<rootDir>/tests/js/config/setup.js"
        ]
    }
}

webpack.mix.js

const mix = require('laravel-mix');

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel application. By default, we are compiling the Sass
 | file for the application as well as bundling up all the JS files.
 |
 */

mix.js('resources/js/app.tsx', 'public/js')
    .react()
    .sass('resources/sass/app.scss', 'public/css')
    .webpackConfig({
        module: {
          rules: [
            {
              test: /\.tsx?$/,
              loader: "ts-loader",
              exclude: /node_modules/
            }
          ]
        },
        resolve: {
          extensions: ["*", ".js", ".jsx", ".vue", ".ts", ".tsx"]
        }
      });

Update

I've added tsconfig.json, package.json and my webpack files. It might be worth mentioning that the react project is within Laravel but I don't see why that would make a difference. Thanks,

0 Answers
Related