【问题标题】:Confusion with Argument of type '{ id: string; name: string; }[]' is not assignable to parameter of type 'SetStateAction<never[]>'与'{ id: string; 类型的参数混淆名称:字符串; }[]' 不可分配给“SetStateAction<never[]>”类型的参数
【发布时间】:2021-03-07 04:23:24
【问题描述】:

我在我正在工作的项目中有这个页面,它加载保存在我的 mongodb 中的所有计划名称,并且还将加载与用户选择的名称相关联的所有值。现在它可以正常工作并且没有任何问题,但是我在页面上遇到了我不知道如何修复的错误。

我将整个页面包含在内,以便您查看发生了什么:

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;
}

我得到的错误在这里:

setLoadedPlans(房间);

错误 - TS2345: 类型参数 '{ id: string;名称:字符串; }[]' 不可分配给“SetStateAction”类型的参数。键入'{ id:字符串;名称:字符串; }[]' 不能分配给类型 'never[]'。键入'{ id:字符串;名称:字符串; }' 不能分配给类型 'never'。

还有:

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

错误 - TS2339:“从不”类型上不存在属性“id”。

我看到其他人对这种类型的事情有问题,并将其归为编译器的问题,但想检查这里是否是这种情况,或者是否有什么我应该改变的?

编辑:

所以我为以下内容分配了一个类型: const { response, rooms }: any = await uiActor.sendMessage(ActorId.Network, MessageId.LoadAllPlan, undefined);

setLoadedPlans((计划:任何) => { const newPlans = plans.filter((element: any) => element.id !== highlightPlan);

这将消除错误,但这是不好的做法吗? 谢谢

【问题讨论】:

  • 请不要简单地将您的错误转储到stackoverflow,想出某种简化的问题重现,并详细说明您不明白的地方。此外,添加一些游乐场/沙盒链接始终是一个好习惯。
  • 嗯,我不知道还能怎么说?认为这很清楚,我不确定为什么我的代码会出现这些错误。如果代码按预期工作,为什么会出现这些错误?
  • 在添加游乐场方面,不确定是否可以这样做,此文件链接到其他一些文件,不同的演员在这里发挥作用,以便从 mongodb 获得所需的内容
  • 是的,这就是我提到简化复制的原因。找出在什么情况下会发生实际错误并进行沙箱复制。会有很大帮助的。
  • 不可能是真的,代码中的每个函数 sn-p 都是出现错误所必需的

标签: reactjs typescript


【解决方案1】:

虽然您所做的事情消除了错误,但问题仍然是这是否解决了问题。

我相信您的问题在于使用 useState 钩子在组件内定义的新状态。

例如,您为空字符串的highlightedPlanerror 以及空数组的loadedPlans 提供了一个默认值。 TypeScript 将尝试使用类型推断来猜测状态的类型。

如果您可以发布屏幕截图或与我们分享您在将鼠标悬停在 highlightedPlanerror 上时所获得的内容,我会对您有所帮助。你应该得到string,因为这是你默认的。如果是这样,那么 TypeScript 已经在那里应用了类型推断,TypeScript 是绝对正确的。

但是,在 loadedPlans 的情况下,TypeScript 看到一个空数组并且不知道应该在该数组中存储什么类型的值,因此默认情况下,TypeScript 会尝试应用类型推断来确定 loadedPlans 是什么.当您将鼠标悬停在loadedPlans 上时,您会得到什么?我们不知道,但我会冒险猜测它说的是&lt;never[]&gt;。那是什么意思?这意味着 TypeScript 不知道该数组中将出现什么样的值,或者更准确地说,因为您在那里放置了一个没有任何类型的空数组,TypeScript 将假定这是一个永远为空的数组。不管怎样,我想这不是你想要的。

TypeScript 无法弄清楚或猜测 loadedPlans 的类型。因此,您可能需要给它一个提示,以便它可以确定要为这个 loadedPlans 状态分配什么类型的值。

您可能想在useState 之后但在([]) 之前尝试尖括号&lt;&gt;,在这些尖括号内描述loadedPlans 将成为哪种类型的状态。例如,如果它是一个字符串,它看起来像这样:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-14
    • 2021-08-01
    • 2021-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-21
    • 2021-05-16
    相关资源
    最近更新 更多