如何为React的withProps函数正确定义类型?

时间:2019-05-18 22:16:44

标签: reactjs typescript

这就是我所拥有的:

export function withProps<P,U extends Partial<P>>(component: React.ComponentType<P>, defaultProps: U): React.FunctionComponent<P & U> {
    return props => React.createElement(component, {...defaultProps, ...props});
}

这是我的用法尝试:

a不需要用于Comp2

我尝试将定义更新为

React.FunctionComponent<Omit<P,keyof U>>

但它也不喜欢:

我认为正确的输出道具应该是Omit<P,keyof U> & U。即,我们删除了所有默认道具,然后将它们作为Partial(全部可选)添加回去,但是我不知道如何使它起作用。

在这里尝试:https://codesandbox.io/s/crazy-monad-pzbve

3 个答案:

答案 0 :(得分:1)

这有点棘手。为了分离提供的属性,需要更改合并类型的声明,例如:TProps & TDefaultProps。此组合类型还需要Omit的主要参数。类型TPropsTDefaultProps分开后,它们将没有任何共同的属性。因此,不可能将值defaultPropsprops都分配给同一对象。因此,至少需要一个as any

function withProps<TProps, TDefaultProps>
  (component: React.ComponentType<TProps & TDefaultProps>, defaultProps: TDefaultProps):
     React.FC<Omit<TProps & TDefaultProps, keyof TDefaultProps>> {
       return props => React.createElement(component, { ...defaultProps as any, ...props});
}

答案 1 :(得分:1)

我接受了您发布的example并进行了一些更改:

  • 我将withProps更改为咖喱函数,就像您在recompose中看到的那样,该函数使用默认的props并返回高阶分量。
  • Omit的键入略有错误;第二个类型参数应以TypeScript 3.5的方式扩展keyof any。原因是Omit的后置条件是“返回的类型将不包含任何这些键”,但不具有“给定类型必须具有所有这些键”的先决条件。这使得Omit在更广泛的场景中很有用。
  • 返回的组件需要接受Partial<TDefaultProps>,而不是TDefaultPropsTDefaultProps没有undefined属性,因此它们都是“必需”的。 Partial<TDefaultProps>允许它们是可选的(因为它们是默认设置)。
  • 您需要将对象传播之一转换为TProps。原因是open issue

这里是result

const defaultProps = <DefaultProps extends object>(defaults: DefaultProps) => <
  Props extends Partial<DefaultProps>
>(
  Component: React.ComponentType<Props>
) => (props: Omit<Props, keyof DefaultProps> & Partial<DefaultProps>) => (
  <Component {...defaults} {...props as Props} />
);

答案 2 :(得分:0)

这给出了迄今为止最好,最全面的结果

export function withProps<TProps extends Record<string,any>, TDefaultProps extends Partial<TProps>=Partial<TProps>>(component: React.ElementType<TProps>, defaultProps: TDefaultProps) {
    const C = (props:TProps) => React.createElement(component, {...defaultProps, ...props});
    if (process.env.NODE_ENV !== 'production') {
        C.displayName = `withProps(${getDisplayName(component)}, ...)`;
    }
    return C as React.FunctionComponent<Omit<TProps, keyof TDefaultProps> & Partial<TDefaultProps>>;
}

如果您尝试设置不存在的默认道具,则会抛出错误,允许您忽略默认道具,并允许您覆盖默认道具。

起初必须在最后一行使用Partial<TDefaultProps>确实使我感到困惑,因为我以为我已经将其定义为Partial,但是后来我意识到它扩展了 Partial<TProps>但当实现时,可选性有效地降低了。