创建一个通用上下文,允许正确推断其中的子级

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

我在思考如何创建通用上下文时遇到了一些麻烦。 基本上我想要的是能够将一个值传递给根,然后让孩子们推断正确的类型,这可能吗?我知道这很有可能,因为

TabHeaderProps
TabContextProps
TabRootProps
之间没有任何联系。

这是一个有效的简化版本,但它比我想要的更详细。

import React, { Dispatch, SetStateAction, useState } from 'react';

type Headers = 'Foo' | 'Bar' | 'Baz';
const defaultValue: Headers = 'Foo';

type TabsContextProps<T = any> = {
  activeTab: T;
  setActiveTab: Dispatch<SetStateAction<T | undefined>>;
};

const TabsContext = React.createContext<TabsContextProps | undefined>(
  undefined,
);

type TabsRootProps<T> = {
  defaultValue: T;
  children: React.ReactNode;
};

export function TabsRoot<T>({ children }: TabsRootProps<T>) {
  const [activeTab, setActiveTab] = useState<T>();

  return (
    <TabsContext.Provider
      value={{
        setActiveTab,
        activeTab,
      }}
    >
      {children}
    </TabsContext.Provider>
  );
}

function useTabsRootContext<T>(): TabsContextProps<T> {
  if (!React.useContext(TabsContext)) {
    throw new Error('useTabsRootContext must be used inside TabsRoot');
  }
  return React.useContext(TabsContext) as TabsContextProps<T>;
}

type TabHeaderProps<T> = {
  value: T;
};

const TabsHeader = <T,>({ value }: TabHeaderProps<T>) => {
  const { activeTab } = useTabsRootContext<T>();
  if (!activeTab !== value) {
    return null;
  }
  return <p>Im Active</p>;
};

const Tabs = () => {
  <TabsRoot<Headers> defaultValue={defaultValue}>
    <TabsHeader<Headers> value="Baz" /> {/* This work but i preferably want this to be infered based on the TabsRootType */}
  </TabsRoot>;
};

理想情况下我想要它:

const Tabs = () => {
  <TabsRoot defaultValue={defaultValue}>
    <TabsHeader value="Baz" />
    <TabsHeader value="error" /> {/* I want this to throw an error */}
  </TabsRoot>;
};
reactjs typescript typescript-generics react-typescript
1个回答
0
投票

不幸的是,这确实是不可能的:

  • React 组件实例除了通过它们的 props 和 context 之外,对它们的父组件一无所知。在您的情况下,您没有通过道具建立明确的联系,仅与上下文建立联系
  • 但是 TypeScript 泛型类型参数推断仅发生在函数调用或类构造函数的参数中(也适用于 React 组件实例 props)。因此 React 上下文无法影响类型推断
© www.soinside.com 2019 - 2024. All rights reserved.