在 React Hook 中基于动态格式定义和断言返回类型

问题描述 投票:0回答:1

问题描述:

我有一个自定义的 React hook

useFetchSelectOptions
,它可以获取数据并将其格式化为可选选项。根据
returnForm
参数,选项需要为
SelectOption[] | null
或 `Record | 类型null,但绝不是两者的混合。

我想确保钩子内

options
的返回类型与指定的
returnForm
严格匹配。例如:

  • 如果
    returnForm
    'arr'
    ,选项应为
    SelectOption[] | null
    类型。
  • 如果
    returnForm
    'dict'
    ,选项应为
    Record<string, string> | null
    类型。

目前,由于钩子中的条件格式,

options
类型可能是
Record<string, string> | SelectOption[] | null
,这可能会导致该钩子的使用者产生歧义。

目标:

我想在钩子内部实现断言机制,以确保

options
严格遵守基于
returnForm
参数确定的类型。这样,使用钩子的消费者就可以放心地依赖推断的类型,而无需额外的类型检查。

代码示例:

import { useState, useEffect } from 'react';

export interface SelectOption {
  label: string;
  value: string;
}

// Define a type for the return form
type ReturnForm = 'dict' | 'arr';

export function useFetchSelectOptions<T extends { name: string; id: string }>(
  fetchData: () => Promise<T[]>,
  returnForm: ReturnForm = 'arr', // Default to array format if not specified
): [T[] | null, SelectOption[] | Record<string, string> | null] {
  const [data, setData] = useState<T[] | null>(null);

  useEffect(() => {
    const fetchDataAndMapToOptions = async () => {
      try {
        const fetchedData = await fetchData();
        setData(fetchedData);
      } catch (error) {
        console.error('Error fetching data:', error);
        setData(null);
      }
    };

    fetchDataAndMapToOptions();
  }, [fetchData]);

  let options: SelectOption[] | Record<string, string> | null = data
    ? data.map((item) => ({ label: item.name, value: item.id }))
    : null;

  // Assertion to strictly type 'options' based on 'returnForm'
  if (returnForm === 'dict') {
    options = options?.reduce(
      (acc, curr) => {
        if (curr) {
          acc[curr.value] = curr.label;
        }
        return acc;
      },
      {} as Record<string, string>,
    ) ?? null;
  }

  return [data, options];
}

补充说明:

我在

useFetchSelectOptions
挂钩中添加了基本类型断言,以基于
options
参数细化
returnForm
的类型。这可确保
options
将符合预期的
SelectOption[] | null
Record<string, string> | null
,具体取决于指定的
returnForm

我正在寻求有关此方法的反馈以及任何潜在的改进或替代策略,以在钩子的上下文中实现严格的

options
键入。

感谢您的协助!

reactjs typescript react-hooks typescript-typings typescript-generics
1个回答
0
投票

使用钩子的消费者可以放心地依赖推断的类型,而无需额外的类型检查。

因为钩子的返回类型已经输入为

[T[] | null, SelectOption[] | Record<string, string> | null]
,所以调用者将看到这一切。这不是您要找的东西,IIUC?

钩子内部的断言机制

无论在内部做什么,函数都不会影响“外部”,因为返回类型已经定义,如上所述。 TS只会检查返回的实际值是否满足所述返回类型。


如果您希望调用者看到与

returnForm
值对应的返回类型,那么您应该研究 Hook 函数签名。对于您的情况,函数重载可能是最合适的:

export function useFetchSelectOptions<T extends { name: string; id: string }>(fetchData: () => Promise<T[]>, returnForm?: "arr"): [T[], SelectOption[] | null]
export function useFetchSelectOptions<T extends { name: string; id: string }>(fetchData: () => Promise<T[]>, returnForm: "dict"): [T[], Record<string, string> | null]
export function useFetchSelectOptions<T extends { name: string; id: string }>(
    fetchData: () => Promise<T[]>,
    returnForm: ReturnForm = 'arr', // Default to array format if not specified
): [T[] | null, SelectOption[] | Record<string, string> | null] {
 // Implementation (untouched)
}

const arr = useFetchSelectOptions(async () => []);
//    ^? [never[], SelectOption[] | null]

const dict = useFetchSelectOptions(async () => [], "dict");
//    ^? [never[], Record<string, string> | null]

游乐场链接

© www.soinside.com 2019 - 2024. All rights reserved.