ts: 'Props' 可以用与其他类型无关的任意类型实例化

IT技术 reactjs typescript firebase
2021-05-25 01:10:23
const withFirebase = <Props extends {firebase: Firebase}>(
  Component: React.ComponentType<Props>
): ComponentType<Omit<Props, "firebase">> => (props) => (
  <FirebaseContext.Consumer>
    {(firebase) => <Component {...props} firebase={firebase} />}
  </FirebaseContext.Consumer>
);

export default withFirebase;

这里

<Component {...props} firebase={firebase} />

抛出以下typescript错误

Type 'Pick<Props, Exclude<keyof Props, "firebase">> & { firebase: Firebase | null; children?: ReactNode; }' is not assignable to type 'IntrinsicAttributes & Props & { children?: ReactNode; }'.
  Type 'Pick<Props, Exclude<keyof Props, "firebase">> & { firebase: Firebase | null; children?: ReactNode; }' is not assignable to type 'Props'.
    'Props' could be instantiated with an arbitrary type which could be unrelated to 'Pick<Props, Exclude<keyof Props, "firebase">> & { firebase: Firebase | null; children?: ReactNode; }

添加了 Omit<Props, "firebase"> 以避免在 Wrapped 组件导入中出现所需的 prop 错误。

喜欢

const App = () => {
  return (
    <ItemWithFirebase /> // If not omit is available this will throw prop firebase not available error
  )
}

const Item: FC<{firebase: Firebase}> = ({firebase}) => {
...
}

const ItemWithFirebase = withFirebase(Item);

我已经铸造了如下传播props

<Component {...(props as Props)} firebase={firebase} />}

但我不确定我是否做得对。您能否让我知道是否有其他方法可以解决此错误?

1个回答

这在编写 HOC 时一直出现。您正在查看错误,它说“我们采用Props,我们删除Props['firebase'],我们添加{firebase: Firebase | null},我们不确定这个对象是否可以分配给Props”。您可能会想,“如果我删除firebase然后又添加回来,那当然是一样的事情”。 从技术上讲Props extends {firebase: Firebase}意味着这Props['firebase']可能比 更具体Firebase,在这种情况下,您提供给它的value是不够的。这种奇怪的边缘情况是您出错的两个原因之一。

另一个原因是Props不允许firebasenull,但Consumer说它可以有Firebasenull

但是在 99.9% 的情况下它是相同的,所以可以{...(props as Props)}像你在这里所做的那样断言您可能想要扩展Props为 allow null,但如果您知道它不会出现null在您的应用程序中,那么这不是问题。

如果让泛型Props代表没有firebase. firebase我们没有从返回中删除,而是将其添加到Component. 我们Omit的任何现有定义,firebaseProps这就排除在边缘的情况下Component,需要的一定的valuefirebase比我们提供其他。

const withFirebase = <Props extends {}>(
  Component: React.ComponentType<Omit<Props, 'firebase'> & {firebase: Firebase | null}>
): ComponentType<Props> => (props) => (
  <FirebaseContext.Consumer>
    {(firebase) => <Component {...props} firebase={firebase} />}
  </FirebaseContext.Consumer>
);