0
votes

I have this page in project I am working that loads all the names of plans saved in my mongodb and will also load all the values with that are associated with the name chosen by the user. Now it works correctly and with no issues but I am getting errors on the page that I am not sure how to fix.

I'm including the whole page so you can see what is happening:

interface Props {
    isVisible: boolean,
    closeDialog: () => void
}

export function LoadDialog({ isVisible, closeDialog }: Props) {
    const uiActor: Actor = React.useContext(uiActorContext);
    const [highlightedPlan, setHighlightedPlan] = React.useState('');
    const [loadedPlans, setLoadedPlans] = React.useState([]);
    const [isLoading, setLoading] = React.useState(false);
    const [error, setError] = React.useState('');

    React.useEffect(() => {
        if (!isVisible) {
            setHighlightedPlan('');
            setError('');
            setLoading(false);
        } else {
            (async () => {
                const { response, rooms } = await uiActor.sendMessage(ActorId.Network, MessageId.LoadAllPlan, undefined);

                switch (response) {
                    case ApiResponse.Database:
                        setError('There was a problem connecting to the database');
                        break;
                    case ApiResponse.Success:
                        setLoadedPlans(rooms);
                        break;
                    default:
                        break;
                }
            })();
        }
    }, [isVisible]);

    const handleLoadClick = React.useCallback(async () => {
        if (highlightedPlan === '') {
            setError('Please select a plan from the list');
            return;
        }

        setLoading(true);
        const planData = await uiActor.sendMessage(ActorId.Network, MessageId.LoadPlan, highlightedPlan);
        const response = await uiActor.sendMessage(ActorId.Main, MessageId.CreateLoadedPlan, planData);

        switch (response) {
            case ApiResponse.Database:
                setError('There was a problem connecting to the database');
                break;
            case ApiResponse.Success:
                closeDialog();
                break;
            default:
                break;
        }
    }, [highlightedPlan]);

    const handleRemoveClick = React.useCallback(async () => {
        if (highlightedPlan === '') {
            setError('Please select a plan from the list');
            return;
        }

        setLoading(true);
        const response = await uiActor.sendMessage(ActorId.Network, MessageId.RemovePlan, highlightedPlan);

        switch (response) {
            case ApiResponse.Database:
                setError('There was a problem connecting to the database');
                break;
            case ApiResponse.Success:
                setLoadedPlans((plans) => {
                    const newPlans = plans.filter((element) => element.id !== highlightedPlan);
                    setHighlightedPlan(newPlans.length ? newPlans[0].id : '');
                    return newPlans;
                });
                setLoading(false);
                setError('');
                break;
            default:
                break;
        }
    }, [highlightedPlan]);

    const handlePlanChange = React.useCallback((event) => {
        setHighlightedPlan(event.target.value);
    }, []);

    return isVisible ? (
        <Dialog>
            <div className='card-body'>
                <h5 className='card-title'>Load Plan</h5>
                <form method='post' onSubmit={(event) => event.preventDefault()}>
                    <div className='form-group'>
                        <ExtendLabel htmlFor='nameElement'>
                            Select the plan you want
                            <select
                                disabled={isLoading}
                                defaultValue=''
                                onChange={(event) => handlePlanChange(event)}
                                className={`form-control${error !== '' ? ' is-invalid' : ''}`}
                                id='nameElement'
                            >
                                <option value='' disabled>Select a plan</option>
                                {loadedPlans.map(({ id, name }) => <option key={id} value={id}>{name}</option>)}
                            </select>
                            <div className='invalid-feedback'>{error}</div>
                        </ExtendLabel>
                    </div>
                    <div className='btn-group mr-2'>
                        <Button type='submit' onClick={() => handleLoadClick()} disabled={isLoading}>Load Plan</Button>
                        <Button className='secondary' onClick={() => handleRemoveClick()} disabled={isLoading}>Remove Plan</Button>
                    </div>
                    <Button className='danger ml-2' onClick={() => closeDialog()} disabled={isLoading}>Cancel</Button>
                </form>
            </div>
        </Dialog>
    ) : null;
}

The errors I am getting are here:

setLoadedPlans(rooms);

Error - TS2345: Argument of type '{ id: string; name: string; }[]' is not assignable to parameter of type 'SetStateAction<never[]>'.   Type '{ id: string; name: string; }[]' is not assignable to type 'never[]'.     Type '{ id: string; name: string; }' is not assignable to type 'never'.

And:

const newPlans = plans.filter((element) => element.id !== highlightedPlan); setHighlightedPlan(newPlans.length ? newPlans[0].id : '');

Error - TS2339: Property 'id' does not exist on type 'never'.

I have seen other people have issues with this type of thing and it being put down as a problem with the compiler but want to check if that's the case here or if there's something that I should change?

Edit:

So I have assign a type any to the following: const { response, rooms }: any = await uiActor.sendMessage(ActorId.Network, MessageId.LoadAllPlan, undefined);

setLoadedPlans((plans: any) => { const newPlans = plans.filter((element: any) => element.id !== highlightedPlan);

this will remove the errors, but is this bad practise to do? Thanks

1
Please, don't simply dump your errors into stackoverflow, come up with some kind of simplified reproduction of the problem and elaborate on what you do not understand. Also, it is always a good practice to add some playground/sandbox link. - Temoncher
Well I wasn't sure how else to put it? Thought it was quite clear, I'm not sure why I'm getting these errors on my code. Why am I getting these errors if the code is working as intended? - lross12
In terms of adding a playground, not sure if that can be done with this, this file links to a few other files, different actors are at play here in order to get what is required from the mongodb - lross12
Yes, that is why I mentioned simplified reproduction. Figure out in what cases actual error occurs and make sandbox repro. It will help a lot. - Temoncher
It can't be real, that every function in your code snippet is necessary for error to appear - Temoncher

1 Answers

1
votes

While what you did removed the error, the question remains whether that solved the problem.

I believe your problem to be in the new pieces of state being defined inside your component using the useState hook.

For example, you provided a default value for state for highlightedPlan and error of empty string and for loadedPlans of empty array. TypeScript is going to try to use type inference to guess what the type of state is.

It would help me help you if you could have posted a screenshot or shared with us what you get when you mouse over highlightedPlan and error. You should get string because that is what you defaulted it to. If that is the case, then TypeScript has applied type inference there and TypeScript is absolutely correct.

However, in the case of loadedPlans, TypeScript sees an empty array and has no idea what type of value should be stored at that array, so by default TypeScript tries to apply type inference to figure out what loadedPlans is. What do you get when you mouse over loadedPlans? We don't know, but I would hazard a guess that it says something like <never[]>. What does that mean? It means TypeScript has no idea what kind of value is going to be present inside that array or more precisely because you placed an empty array there without any type, TypeScript is going to assume that this is an array that is forever empty. Either way, I would imagine that is not what you want.

TypeScript has not been able to figure out or guess what the type of loadedPlans is going to be. So you probably need to give it a hint so it can figure out what type of value is going to be assigned to this loadedPlans piece of state.

You may want to try angle brackets <> right after useState but before the ([]) and inside those angle brackets describe what type of piece of state that loadedPlans is going to be. For example, if it's a string it would look like so:

const [loadedPlans, setLoadedPlans] = useState<string[]>([]);