为包装 <App/> 的上下文提供程序键入道具?

Type props for a context provider wrapping <App/>?

我正在定义一个上下文提供程序来包装我的 <App/> 组件,如下所示:

// index.ts
ReactDOM.render(
  <ApolloProvider client={client}>
    <React.StrictMode>
      <AuthProvider>
        <App />
      </AuthProvider>
    </React.StrictMode>
  </ApolloProvider>,
  document.getElementById('root')
);

我通过传递从 React.ReactNode 类型的 props 解构的 {children} 使上下文提供程序定义工作,并且 return 将子项包装在两个 <AuthContext.Provider> 标签之间,例如这个:

// src/context/AutContext.ts

// Context definition
const AuthContext = React.createContext<{currentUser: User} | undefined>(undefined);

// Context provider wrapper definition:
const AuthProvider = ({ children }: { children: React.ReactNode }) => {
    const { currentUser } = useCurrentUse();
  
    return (
      <AuthContext.Provider value={{ currentUser }}>
        {children} // <- note the different ways of passing children to the Provider
      </AuthContext.Provider>
    );  
  };
    

但我正在尝试通过将 <AuthContext.Provider/> 减少为一行来简化代码,现在我正在努力定期传递 props,但类型为 any:

// Context provider wrapper definition (one liner variant):
const AuthProvider = (props: any) => { // <- any type. props instead of destructured {children}
  const { currentUser } = useCurrentUser();

  return <AuthContext.Provider value={{ currentUser }} {...props} />; // <- spread one liner
};

知道我应该如何在第二个变体中输入 props 吗?我试过推断它,但结果不起作用(而且一团糟),并且使用 React.ReactNode 作为类型仅适用于 {children},不适用于整个 props.

@types/react 中我找到了一个 ProviderProps<T> 可能是解决方案,但如果是,我仍然不知道用什么替换 T

查看 type definitionProviderProps<T> 通用 T 用于键入 value 属性。

这意味着您将提供与 React.createContext<T>() 相同的 T

简单方法:

// We know from inspecting the ProviderProps type that it has two properties
// The first property value is not to be passed in.
// The second property children is an optional set of react nodes.
// The React.FunctionComponent type with no generic added only has a prop of type 
// children?: React.ReactNode.
// This will make the props of AuthProvider compatible with the props of AuthContext.Provider.
const AuthProvider: React.FunctionComponent = (props) => {
    const { currentUser } = useCurrentUser();
  
    return (
      <AuthContext.Provider value={{ currentUser }} {...props} />
    );
};

更复杂的方法:

type ContextValue = {currentUser: User} | undefined;

// depending on your version of typescript Omit might not like types with generics
// the work around for this is to create a wrapping type around Omit to trick it into
// thinking that it is getting a type it approves of.
// If this does not effect your version of typescript just use:
// Omit<ProviderProps<ContextValue>, 'value'>
type OmitValue<T> = Omit<T, 'value'>

const AuthContext = React.createContext<ContextValue>(undefined);

// We do not control the type ProviderProps, this may change in the future.
// To give better future proofing we can use the ProviderProp type and remove the
// properties we do not want to be changed (value in this case) using Omit.
// This means that any additional properties added to ProviderProps in the future
// will be valid for AuthProvider, but at this point in time it will just be
// children.
const AuthProvider: React.FunctionComponent<OmitValue<ProviderProps<ContextValue>>> = (props) => {
    const { currentUser } = useCurrentUser();
  
    return (
      <AuthContext.Provider value={{ currentUser }} {...props} />
    );
};