Typescript错误,React高阶组件

huangapple go评论84阅读模式
英文:

Typescript Error, React Higher order Component

问题

长期的React开发者尝试适应TypeScript。

在这个简单的高阶组件上,我遇到了正确的类型定义问题。

/**
 * 返回一个带有默认类名集合的组件
 */

function withDefaultClasses<T extends JSX.IntrinsicAttributes>(
  Component: React.FunctionComponent<T>,
  defaultClassNames: string,
) {
  
   type Props = T & { className?: string };

  return function withClasses(props: T & { className?: string }) {
    const { className, ...rest } = props;

    // 在连接之前检查className是否存在
    const classNames = className
      ? defaultClassNames + ' ' + className
      : defaultClassNames;

    return <Component className={classNames} {...rest} />;
  };
}

我遇到了以下错误:

类型 '{ className: string; } & Omit<Props, "className">' 不能赋值给类型 'IntrinsicAttributes & T'。
  类型 '{ className: string; } & Omit<Props, "className">' 不能赋值给类型 'T'。
    'T' 可能会被赋予一个与 '{ className: string; } & Omit<Props, "className">' 无关的任意类型。

我认为这可能是因为泛型组件可能不能具有className属性。

我感到困惑,我原本期望不会看到TypeScript错误。

英文:

Long time React developer trying to adapt to typescript.

I am having issues getting the correct typing on this simple Higher order component

/**
 *  Returns a component that will have a default set of classnames
 */

function withDefaultClasses&lt;T extends JSX.IntrinsicAttributes&gt;(
  Component: React.FunctionComponent&lt;T&gt;,
  defaultClassNames: string,
) {
  
   type Props = T &amp; { className?: string };

  return function withClasses(props: T &amp; { className?: string }) {
    const { className, ...rest } = props;

    // Check if className is present or not before concatenating
    const classNames = className
      ? defaultClassNames + &#39; &#39; + className
      : defaultClassNames;

    return &lt;Component className={classNames} {...rest} /&gt;;
  };
}

I am getting the following error

Type &#39;{ className: string; } &amp; Omit&lt;Props, &quot;className&quot;&gt;&#39; is not assignable to type &#39;IntrinsicAttributes &amp; T&#39;.
  Type &#39;{ className: string; } &amp; Omit&lt;Props, &quot;className&quot;&gt;&#39; is not assignable to type &#39;T&#39;.
    &#39;T&#39; could be instantiated with an arbitrary type which could be unrelated to &#39;{ className: string; } &amp; Omit&lt;Props, &quot;className&quot;&gt;&#39;.

I believe it it due to the fact that the generic component could not have the className property perhaps.

I'm at a loss

I was expecting not to see Typescript errors

答案1

得分: 1

在这个高阶函数中,你试图扩展一个React组件,添加额外的props。你面临的问题是TypeScript不知道你提供的组件(Component)是否接受className prop。

你可以这样做,创建一个新类型,扩展T并包含className。像这样:

function withDefaultClasses<T extends React.ComponentProps<any>>(
  Component: React.ComponentType<T>,
  defaultClassNames: string,
) {
  return function withClasses(props: T) {
    const { className, ...rest } = props;

    // 在连接之前检查className是否存在
    const classNames = className
      ? defaultClassNames + ' ' + className
      : defaultClassNames;

    // 我们展开其余的props并添加我们连接的className
    return <Component {...rest as T} className={classNames} />;
  };
}

在上面的代码中,React.ComponentProps<any>允许我们确保T始终包括className作为可能的属性。React.ComponentType<T>是一个更通用的组件类型,允许包括函数和类组件。在其余的props上使用as T断言可以让TypeScript理解这些属性是为组件而设计的。

这应该解决了TypeScript错误。它假设你要包装在withDefaultClasses中的原始组件(或组件)可以接受className prop。如果不是这种情况,你可能需要相应地调整类型或组件。

英文:

In this higher-order function, you're trying to extend a React component with additional props. The issue you're facing is that TypeScript doesn't know that the component you're providing (Component) accepts a className prop.

What you can do is to make a new type that extends T and includes className. Like this:

function withDefaultClasses&lt;T extends React.ComponentProps&lt;any&gt;&gt;(
  Component: React.ComponentType&lt;T&gt;,
  defaultClassNames: string,
) {
  return function withClasses(props: T) {
    const { className, ...rest } = props;

    // Check if className is present or not before concatenating
    const classNames = className
      ? defaultClassNames + &#39; &#39; + className
      : defaultClassNames;

    // We spread the rest props and add our concatenated className
    return &lt;Component {...rest as T} className={classNames} /&gt;;
  };
}

In the above code, React.ComponentProps&lt;any&gt; allows us to ensure T always includes className as a possible property. React.ComponentType&lt;T&gt; is a more generic type for components, allowing for both function and class components. The as T assertion on the rest props allows TypeScript to understand that the properties are meant for the Component.

This should resolve the TypeScript error. It assumes that the original component (or components) you are wrapping with withDefaultClasses can accept a className prop. If that's not the case, you may need to adjust the types or the components accordingly.

huangapple
  • 本文由 发表于 2023年8月4日 03:18:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/76831040.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定