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,