使用上下文和打字稿来响应自定义挂钩:类型“选项”上不存在属性“地图”

时间:2020-02-05 17:41:46

标签: javascript reactjs typescript react-hooks react-context

我正在开发一个React应用程序,其中包含可通过Context访问的自定义挂钩。该应用程序使用Typescript并定义自定义类型,例如Option,这是一个表示Radio元素或Checkbox状态的对象。

从广义上讲,这些是代码遵循的步骤:

  • 在包含自定义状态挂钩的组件树顶部创建上下文
  • 自定义钩子包含自定义Typescript类型(选项)
  • 在树下,组件读取自定义状态钩子以渲染Radios或Checkboxes

首先,它定义带有上下文的自定义挂钩,以使其可用于其余组件。它还包括自定义选项类型:

import React from "react";

// Custom Option type
export type Option = {
    name: string;
    enabled: boolean;
    checked: boolean;
};

const FiltersContext = React.createContext<Option[] | null>(null);

function useFilters() {
    const context = React.useContext(FiltersContext);
    if (!context) {
        throw new Error(`useFilters must be used within a FiltersProvider`);
    }
    const [filters, setFilters] = context;

    return {
        filters,
        setFilters
    };
}

function FiltersProvider(props: any) {
    // Prepare default options array
    const options: Option[] = [
        {
            name: "Option 1",
            enabled: true,
            checked: true
        },
        {
            name: "Option 2",
            enabled: true,
            checked: false
        }
    ];

    // Assigns default options
    const [filters, setFilters] = React.useState<Option[]>(options);
    const value = React.useMemo(() => [filters, setFilters], [filters]);

    return <FiltersContext.Provider value={value} {...props} />;
}

export { FiltersProvider, useFilters };

以后在树上和树下,我都有一个读取该自定义钩子状态的组件。问题来了:

import * as React from "react";
import { Option, useFilters } from "../../context/use-filters";

const Options: React.FC = () => {
    const { filters } = useFilters();

    return (
        <Wrapper>
            {filters.map((option: Option, key: number) => (
                <OptionWrapper key={key}>
                    <RadioButton defaultChecked={false} name={option.name} disabled={false} onClick={() => {}} />
                    <Label>{option.name}</Label>
                </OptionWrapper>
            ))}
        </Wrapper>
    );
};

export default Options;

该代码从filters获取useFilters,然后通过map来创建RadioButton组件。打字稿抱怨说:

Property 'map' does not exist on type 'Option'

据我所知,filters被检测为Option类型,而不是选项数组。

如果我在filters之前遍历return,则选项将显示在控制台上,但Typescript仍会抱怨该错误:

filters.map((option: Option) => console.log(option.name));

我确定我误解了一些非常重要的东西,所以我先请您谅解,但是如果您能对此有所了解,我将非常感激!

再次感谢!

1 个答案:

答案 0 :(得分:1)

您的上下文类型错误,应该是这样的:

const FiltersContext = React.createContext<[Option[], Dispatch<SetStateAction<Option[]>>] | null>(null);

您的上下文将意味着您仅返回过滤器作为上下文值,但同时还返回setFilters函数,因此您也需要考虑这一点。 setFilter的键入来自:

import { Dispatch, SetStateAction } from 'react';