Typescript:如何将setStateAction作为可以接受多种可能类型的prop?

oxosxuxt  于 2023-05-01  发布在  TypeScript
关注(0)|答案(2)|浏览(143)

我有多个页面,它们都有不同类型的useState:

//Page 1 ...
const [ShoppingListKey, setShoppingListKey] = useState<keyof ShoppingList>();

//Page 2 ...
const [isTrue, setIsTrue] = useState<boolean>(false);

//Page 3 ... 
const [String, setString] = useState<string>('');

所以,我有一个组件,我想让它做的是从其父组件中获取目标状态值,并将其父组件的状态设置为目标值:

interface ChildProps {
  targetStateValue: keyof ShoppingList | boolean | string | undefined;
  setStateFunc: Dispatch<React.SetStateAction<keyof ShoppingList | boolean | string | undefined>>
}
export const Child = ({targetStateValue, setStateFunc}: ChildProps) => {
  <button OnClick={()=>{setStateFunc(targetStateValue);}}>BUTTON</button>
}

在ShoppingList父级中:

<Child
  setStateFunc={setShoppingListKey} //ERROR
  targetStateValue={something}
/>

The Error说道:类型'Dispatch〈SetStateAction〈keyof ShoppingList|undefined〉〉'不能分配给类型'Dispatch〈SetStateAction〈string|布尔|未定义〉〉'

vql8enpb

vql8enpb1#

您可以使用generic组件。这样组件将在多种类型上工作而不是单个类型。
您可以为子 prop 定义一个通用接口。和一个通用组件,它使用该接口作为其props的类型。

interface ChildProps<T> {
  targetStateValue: T;
  setStateFunc: Dispatch<React.SetStateAction<T>>;
}
export const Child = <T>({
  targetStateValue,
  setStateFunc,
}: ChildProps<T>) => {
  return (
    <button
      onClick={() => {
        setStateFunc(targetStateValue);
      }}
    >
      BUTTON
    </button>
  );
};

使用上面的方法,我们可以在调用/定义时更改T,并且基于此,组件的内部类型将发生变化。
为了简单起见,我为ShoppingList创建了一个简单的接口,并为状态变量ShoppingListKey提供了一个预填充值。代码如下所示:

interface ShoppingList {
  onion: string;
  tomato: string;
}

interface ChildProps<T> {
  targetStateValue: T;
  setStateFunc: Dispatch<React.SetStateAction<T>>;
}
export const Child = <T>({
  targetStateValue,
  setStateFunc,
}: ChildProps<T>) => {
  return (
    <button
      onClick={() => {
        setStateFunc(targetStateValue);
      }}
    >
      BUTTON
    </button>
  );
};

function App() {
  const [ShoppingListKey, setShoppingListKey] =
    useState<keyof ShoppingList>("tomato");

  //Page 2 ...
  const [isTrue, setIsTrue] = useState<boolean>(false);

  //Page 3 ...
  const [String, setString] = useState<string>("");
  console.log({ ShoppingListKey, isTrue, String });
  return (
    <div className="App">
      <Child<keyof ShoppingList>
        targetStateValue={"onion"}
        setStateFunc={setShoppingListKey}
      />
      <Child<boolean> targetStateValue={true} setStateFunc={setIsTrue} />
      <Child<string> targetStateValue={"test"} setStateFunc={setString} />
    </div>
  );
}

CodeSandbox

xdnvmnnf

xdnvmnnf2#

TypeScript可能有太多的推理,你可能只需要为你的解决方案制作一个专用的type来简化你的类型。

export type TargetStateValue = keyof ShoppingList | boolean | string | undefined

现在,您有了一个专用的TypeScript type供您的targetStateValue使用,您可以如下使用它:

interface ChildProps {
  targetStateValue: TargetStateValue;
  setStateFunc: Dispatch<React.SetStateAction<TargetStateValue>>
}

相关问题