React Component PropType is defined but prop is never used eslint error - reactjs

For some reason I am getting the "PropType is defined but prop is never used" lint error in the code bellow:
type LinkType = {
name: string; //PropType is defined but prop is never
href: string; //PropType is defined but prop is never
target?: string; //PropType is defined but prop is never
rel?: string; //PropType is defined but prop is never
};
type MyComponentPropsType = {
links?: LinkType[];
};
function MyComponent({ links }: MyComponentPropsType): ReactElement {
return (
<ul>
{links.map(({ name, href, target, rel }: LinkType) => ( //I'm using the type here
<li key={name}>
<a href={href} rel={rel} target={target}>
{name}
</a>
</li>
))}
</ul>
);
}
For some reason I get the "PropType is defined but prop is never used" and I am using these types, so I want understand why I getting this error.

Related

"Expected 1 arguments, but got 0." for onClick event in React with Typescript

I have a handleClick function that I'm trying to pass as a prop for my onClick event within a component. This event just takes a setState function. I set an interface to type this as "handleClick: React.Dispatch<React.SetStateAction>;" as nothing else worked and would always give errors, so I assumed all was well, until I went ahead with writing the onClick event into the component declaration, when the error in the title appeared.
Here's the relevant code:
interface IProps {
handleClick: React.Dispatch<React.SetStateAction<boolean>>;
icon?: JSX.Element;
}
const NavLinks: React.FC<IProps> = ({ handleClick }) => (
<div className="sidebar_navlinks">
{sidebar_links.map((link) => (
<NavLink key={link.name} to={link.to} onClick={() => handleClick && handleClick()}>
<div className="link">
<link.icon className="icon" />
{link.name}
</div>
</NavLink>
))}
</div>
)
And then with that component I just do something like
<NavLinks handleClick={() => setMenuState(false)} />
How can I best type this so it stops giving the error in the title? I'm not clear why it would expect there's a value when I'm typed it to be something that sets state?
I see stuff online that, more often than not, is assuming the onClick is going to apply to an HTML button element, but I'm just using this to click on react-icons, so I'm even more lost.
handleClick should be of type () => void since setMenuState is wrapped in a function.
interface IProps {
handleClick: () => void;
icon?: JSX.Element;
}
If you passed setMenuState directly like:
<NavLinks handleClick={setMenuState} />
then it can be typed as a setState function

How do I make a route change in React using Typescript?

I am coding along the ZTM course, making a face recognition app, but instead of Javascript, I am using Typescript to build my app, avoiding using any type. I am new to the language and don't fully grasp its nuances, so please advise me on how to resolve the issue below.
The problem is simple. I want the Sign Out page to appear when we click the corresponding button. However, I can't make this task possible like it's made in Javascript.
Let me show you what my code looks like to make it simpler to understand the problem. Firstly, there is my main App component, including its interface and parts that are important to the issue:
interface IAppState {
input: string,
imageUrl: string,
box: Object,
route: string
}
class App extends Component<{title: string}, IAppState> {
constructor(props: {title: string}) {
super(props);
this.state = {
input: '',
imageUrl: '',
box: {},
route: 'signin'
}
}
Here is the part of the main App component that makes the state change and routes us to the main page, including the render() method, where you can see my property onRouteChange:
onRouteChange = ({route}) => {
this.setState({route: route});
}
render() {
return (
<div className="App">
<ParticlesBg type="cobweb" bg={true} />
<Navigation onRouteChange={this.onRouteChange} />
{ this.state.route === 'signin'
? <SignIn onRouteChange={this.onRouteChange}/>
: <>
<Logo />
<Rank />
<ImageLinkForm title='image link form'
onInputChange={this.onInputChange}
onButtonSubmit={this.onButtonSubmit}
/>
<FaceRecognition imageUrl={this.state.imageUrl}/>
</>
}
</div>
);
}
In my Navigation component, there is the Sign Out button, which should route us back to the Sign In page:
interface INavigationProps {
onRouteChange: MouseEventHandler<HTMLInputElement>;
}
const Navigation: FC<INavigationProps> = ({ onRouteChange }) => {
return (
<nav style={{ display: 'flex', justifyContent: 'flex-end' }}>
<p onClick={() => onRouteChange('signin')} className='f3 link dim black underline pa3 pointer'>Sign Out</p>
</nav>
);
}
With a given code the Sign Out button doesn't work. Errors appear.
The first one that's obvious to me is regarding the route element: Binding element 'route' implicitly has an 'any' type.
And the second one that I don't understand how to fix:
Type '({ route }: { route: any; }) => void' is not assignable to type 'MouseEventHandler<HTMLInputElement>'.
Types of parameters '__0' and 'event' are incompatible.
Property 'route' is missing in type 'MouseEvent<HTMLInputElement, MouseEvent>' but required in type '{ route: any; }'.
The last error is in my Navigation component: Argument of type 'string' is not assignable to parameter of type 'MouseEvent<HTMLInputElement, MouseEvent>'.
I was playing with interfaces and types to resolve this, but I couldn't find the solution. How do I make the Sign Out button route us back to the Sign In page?
I have done more research and here's the final error-free code below. Firstly, fixed the line in interface IAppState to:
route: MouseEventHandler<HTMLInputElement> | undefined | string
Then redacted onRouteChange to look like this, stating its types accordingly:
onRouteChange = (route: MouseEventHandler<HTMLInputElement> | undefined | string) => {
return this.setState({route: route});
}
And then final changes were made to the Navigation component:
interface INavigationProps {
onRouteChange: (route: MouseEventHandler<HTMLInputElement> | undefined | string) => void;
}
const Navigation: FC<INavigationProps> = ({ onRouteChange }) => {
return (
<nav style={{ display: 'flex', justifyContent: 'flex-end' }}>
<p onClick={() => onRouteChange('signin')} className='f3 link dim black underline pa3 pointer'>Sign Out</p>
</nav>
);
}
That way I can access Sign In page from the home page, using Sing Out button.

Force react component to only accept a child with a specific type

I have this following component:
interface InputWithButtonProps {
label: string;
children: React.ReactElement<typeof CustomButton>;
}
const InputWithButton = ({
label,
fieldName,
disabled,
children,
}: InputWithButtonProps): JSX.Element => {
return (
<>
<TextField label={label} />
{Children.only(children)}
</>
);
};
export default InputWithButton;
And the code for CustomButton is:
export declare const CustomButton: import("#material-ui/core").ExtendButtonBase<import("#material-ui/core").ButtonTypeMap<{}, "button">>;
What I want from InputWithButton is to only accept one single child of type CustomButton, but specifying the type using React.ReactElement<typeof CustomButton> doesn't do any checks, so the following code will work just fine (Which should throw an error in this case):
<InputWithButton label="some label">
<div>test</div>
</InputWithButton>
The InputWithButton should only accept this:
<InputWithButton label="some label">
<Button>Some button</Button>
</InputWithButton>
I also tried to specify the children type as following:
children: React.ReactElement<ButtonProps>;
Which didn't work either.
How can I solve this?
You need to apply the condition that checks if the children's type is Button or not, consider the code below that will solve your problem if I understand your problem correctly,
interface InputWithButtonProps {
label: string;
children: React.ReactElement<typeof CustomButton>;
}
const InputWithButton = ({
label,
fieldName,
disabled,
children,
}: InputWithButtonProps): JSX.Element => {
return typeof children.type == 'function' &&
children.type.name == "Button" &&
(
<>
<input label={label} />
{children}
</>
);
};
export default InputWithButton;
The component will return nothing if the tag is other than 'Button', you can remove the 'typeof children.type' condition because it only checks if the children is custom made component or an HTML tag.

Using a forwardRef component with children in TypeScript

Using #types/react 16.8.2 and TypeScript 3.3.1.
I lifted this forward refs example straight from the React documentation and added a couple type parameters:
const FancyButton = React.forwardRef<HTMLButtonElement>((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
// You can now get a ref directly to the DOM button:
const ref = React.createRef<HTMLButtonElement>();
<FancyButton ref={ref}>Click me!</FancyButton>;
I get the following error in the last line under FancyButton:
Type '{ children: string; ref: RefObject<HTMLButtonElement>; }' is not
assignable to type 'IntrinsicAttributes & RefAttributes<HTMLButtonElement>'. Property 'children' does not
exist on type 'IntrinsicAttributes & RefAttributes<HTMLButtonElement>'.ts(2322)
It would seem that the type definition for React.forwardRef's return value is wrong, not merging in the children prop properly. If I make <FancyButton> self-closing, the error goes away. The lack of search results for this error leads me to believe I'm missing something obvious.
trevorsg, you need to pass the button properties:
import * as React from 'react'
type ButtonProps = React.HTMLProps<HTMLButtonElement>
const FancyButton = React.forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => (
<button type="button" ref={ref} className="FancyButton">
{props.children}
</button>
))
// You can now get a ref directly to the DOM button:
const ref = React.createRef<HTMLButtonElement>()
<FancyButton ref={ref}>Click me!</FancyButton>
ADDED:
In recent versions of TS and #types/react, you can also use React.ComponentPropsWithoutRef<'button'> instead of React.HTMLProps<HTMLButtonElement>
The answers given by aMarCruz and euvs both work, but they lie to consumers a little bit. They say they accept all HTMLButtonElement props, but they ignore them instead of forwarding them to the button. If you're just trying to merge in the children prop correctly, then you might want to use React.PropsWithChildren instead:
import React from 'react';
interface FancyButtonProps {
fooBar?: string; // my custom prop
}
const FancyButton = React.forwardRef<HTMLButtonElement, React.PropsWithChildren<FancyButtonProps>>((props, ref) => (
<button type="button" ref={ref} className="fancy-button">
{props.children}
{props.fooBar}
</button>
));
FancyButton.displayName = 'FancyButton';
Or explicitly add a children prop:
interface FancyButtonProps {
children?: React.ReactNode;
fooBar?: string; // my custom prop
}
const FancyButton = React.forwardRef<HTMLButtonElement, FancyButtonProps>((props, ref) => (
<button type="button" ref={ref} className="fancy-button">
{props.children}
{props.fooBar}
</button>
));
FancyButton.displayName = 'FancyButton';
Or if you actually want to accept all the button props and forward them (let consumers choose button type="submit", for example), then you might want to use rest/spread:
import React from 'react';
interface FancyButtonProps extends React.ComponentPropsWithoutRef<'button'> {
fooBar?: string; // my custom prop
}
const FancyButton = React.forwardRef<HTMLButtonElement, FancyButtonProps>(
({ children, className = '', fooBar, ...buttonProps }, ref) => (
<button {...buttonProps} className={`fancy-button ${className}`} ref={ref}>
{children}
{fooBar}
</button>
),
);
FancyButton.displayName = 'FancyButton';
The answer given by aMarCruz works well. However, if you also need to pass custom props to the FancyButton, here is how it can be done.
interface FancyButtonProps extends React.ComponentPropsWithoutRef<'button'> {
fooBar?: string; // my custom prop
}
const FancyButton = React.forwardRef<HTMLButtonElement, FancyButtonProps>((props, ref) => (
<button type="button" ref={ref} className="FancyButton">
{props.children}
{props.fooBar}
</button>
));
/// Use later
// You can now get a ref directly to the DOM button:
const ref = React.createRef<HTMLButtonElement>()
<FancyButton ref={ref} fooBar="someValue">Click me!</FancyButton>
Just adding here for completion.
You can use ForwardRefRenderFunction<YourRefType, YourProps> on your component.
Like:
const Component: ForwardRefRenderFunction<YourRef, YourProps> = (yourProps, yourRef) => return <></>
export default fowardRef(Component)

ReactJS typescript error Parameter props implicitly has 'any' type

Following, and adapting the tutorial here, I've hit a snag when trying to define a function to render some HTML.
function Toolbar(props) {
return (
<div>
<button onClick={() => props.onClick()}>Refresh</button>
</div>
);
}
This errors in Typescript, because props is not defined. I understand why I'm getting the error, but what I'm missing is what type should props be?
I believe I should then be able to use this inside another component like this:
function App() {
return (
<div>
<Toolbar onClick={() => alert('hello world')}>Test</Toolbar>
</div>
);
}
And the props is just whatever I specify. This would seem to be borne out here: although that link doesn't mention typescript. So, my question is: how does this feature (that of passing properties into a function or class) work with typescript when, by definition, you don't know what you're passing through?
You should define an interface for the props.
interface Props {
onClick: () => void;
}
function Toolbar(props: Props) {
return (
<div>
<button onClick={() => props.onClick()}>Refresh</button>
</div>
);
}
I also like to define my functional components as an arrow function. And you can use the FC (Functional Component) type definition with the Props generic type. This way you can deconstruct your properties right away.
const Toolbar: React.FC<Props> = ({onClick}) => {
return (
<div>
<button onClick={() => onClick()}>Refresh</button>
</div>
);
}

Resources