reactjs 如何根据JavaScript值推断类型

zqdjd7g9  于 2023-04-20  发布在  React
关注(0)|答案(2)|浏览(85)

我有一个react hook,它根据用户提供的类型 prop 返回过滤器。

interface Props {
    type: 'product' | 'content';
}

function useFilterSelector(props: Props) {
    const { t } = useClientTranslation();

    const queryClient = useQueryClient();
    const [filterSelector] = useState(() => {
        switch (props.type) {
            case 'product':
                return new ProductFilter(t, queryClient);
            case 'content':
                return new ContentFilter(t, queryClient);
        }
    });

    return { filterSelector };
}

这个钩子工作得很好,但问题是我不能得到严格的类型推断。例如,如果开发人员为参数提供“product”

const { filterSelector } = useFilterSelector({ type : "product"})

推断的类型应为

type = ProductFilter

但我得到了

type = ProductFilter | ContentFilter

我试过这个

function useFilterSelector(props: Props) {
    const { t } = useClientTranslation();

    type FilterType = (typeof props)['type'];
    type FilterSelector = FilterType extends 'product'
        ? ProductFilter
        : FilterType extends 'content'
        ? ContentFilter
        : unknown;

    const queryClient = useQueryClient();
    const [filterSelector] = useState<FilterSelector>(() => {
        switch (props.type) {
            case 'product':
                return new ProductFilter(t, queryClient);
            case 'content':
                return new ContentFilter(t, queryClient);
        }
    });

    return { filterSelector };
}

但类型被推断为未知
这个怎么解决?

wwtsj6pe

wwtsj6pe1#

您可以使用基于props.type类型的条件返回类型

interface Props {
    type: 'product' | 'content';
}

interface ProductFilter {
  a: string;
}
interface ContentFilter {
  b: number;
}

interface FilterSelector<T extends Props> {
  filterSelector: T['type'] extends 'product' ? ProductFilter : ContentFilter
}

function useFilterSelector<T extends Props>(props: T): FilterSelector<T> {
  return { filterSelector: {} as any }
}

const pF = useFilterSelector({ type: 'product' })
pF.filterSelector.a
//               ^? (property) ProductFilter.a: string
const cF = useFilterSelector({ type: 'content' })
cF.filterSelector.b
//               ^? (property) ContentFilter.b: number

Playground link

bweufnob

bweufnob2#

如何使用类型Assert,以便typescript使用该类型而不是unknown?

switch (props.type) {
      case 'product':
        return new ProductFilter(t, queryClient) as FilterSelector;
      case 'content':
        return new ContentFilter(t, queryClient) as FilterSelector;
    }

相关问题